< 返回版块

abliger 发表于 2023-03-07 11:10

Tags:闭包

书中的例子:

fn main() {
    let mut list = vec![1, 2, 3];
    println!("Before defining closure: {:?}", list);

    let mut borrows_mutably = || list.push(7);
    // 此处就不能使用 list 变量
    println!("{:?}",list);
    borrows_mutably();
    println!("After calling closure: {:?}", list);
}

编译报错如下 img

评论区

写评论
0xe994a4 2023-03-08 15:06

closure 默认情况下捕获变量的不可变引用,但因为在 closure 内部是 push 操作,所以会捕获变量的可变引用。 在 closure 捕获 list 的可变引用后,直到最后一次调用,否则将一直持有。 那么,按照借用规则:

要么存在多个不可变引用,要么只存在一个可变引用

println! 再想获取 list 的不可变引用就违反借用规则了。

作者 abliger 2023-03-07 17:11

了解了,谢谢

苦瓜小仔 2023-03-07 14:06

是否应该这样理解?

你的确可以通过赋值语句理解(引用以最简单的方式被使用),但具体的做法不对。

复现原问题错误的方式是:

    let mut borrows_mutably = || {
        let mut_list = &mut list;
        mut_list.push(7);
    };
    // 此处就不能使用 list 变量
    let _ = &list; // i.e println!("{:?}",list);
    borrows_mutably();

playground

细节:移动引用而不是移动所有权

8 |     let zzz = list;
  |               ^^^^ move out of `list` occurs here
9 |     borrows_mutably();
  |     --------------- borrow later used here

你移动了 list 的所有权,违反了另一条 借用规则:引用必须使用有效 —— 由于此代码在第 8 行移动 list,第 9 行的独占引用已经失效,从而不能使用。

作者 abliger 2023-03-07 12:14

println!("{:?}",list); 改写为 let z =list;,此时会报这样的错误

error[E0505]: cannot move out of `list` because it is borrowed
 --> src/bin/aa.rs:8:15
  |
5 |     let mut borrows_mutably = || list.push(7);
  |                               -- ---- borrow occurs due to use in closure
  |                               |
  |                               borrow of `list` occurs here
...
8 |     let zzz = list;
  |               ^^^^ move out of `list` occurs here
9 |     borrows_mutably();
  |     --------------- borrow later used here

也就是 第五行可以拆分成

let z = list;
let mut borrows_mutably =|z| z.push(7);

这时再调用 let zzz = list; 才会发生上述错误.

是否应该这样理解?

--
👇
苦瓜小仔: &borrows_mutably 携带 &mut list,并跨越下一行的 &list,进行了使用,导致独占引用与共享引用并存,违反借用规则。

在使用前为何变成了不可变引用

这不对,使用 borrows_mutably 就意味着使用 &mut list。出现 immutable borrow的地方,编译器很清楚地告诉你是在 println! 内。

5 |     let mut borrows_mutably = || list.push(7);
  |                               -- ---- first borrow occurs due to use of `list` in closure
  |                               |
  |                               mutable borrow occurs here
6 |     // 此处就不能使用 list 变量
7 |     println!("{:?}",list);
  |                     ^^^^ immutable borrow occurs here
8 |     borrows_mutably();
  |     --------------- mutable borrow later used here
苦瓜小仔 2023-03-07 11:29

&borrows_mutably 携带 &mut list,并跨越下一行的 &list,进行了使用,导致独占引用与共享引用并存,违反借用规则。

在使用前为何变成了不可变引用

这不对,使用 borrows_mutably 就意味着使用 &mut list。出现 immutable borrow的地方,编译器很清楚地告诉你是在 println! 内。

5 |     let mut borrows_mutably = || list.push(7);
  |                               -- ---- first borrow occurs due to use of `list` in closure
  |                               |
  |                               mutable borrow occurs here
6 |     // 此处就不能使用 list 变量
7 |     println!("{:?}",list);
  |                     ^^^^ immutable borrow occurs here
8 |     borrows_mutably();
  |     --------------- mutable borrow later used here
1 共 5 条评论, 1 页