什么时候应该将mut添加到闭包中?

Daj*_*avu 8 rust

fn main() {
    let mut a = String::from("a");
    let closure = || {
        a.push_str("b");
    };

    closure();
}
Run Code Online (Sandbox Code Playgroud)

这不会编译:

error[E0596]: cannot borrow immutable local variable `closure` as mutable
 --> src/main.rs:7:5
  |
3 |     let closure = || {
  |         ------- consider changing this to `mut closure`
...
7 |     closure();
  |     ^^^^^^^ cannot borrow mutably
Run Code Online (Sandbox Code Playgroud)

如果我a在闭包中返回而不添加mut,则可以编译:

fn main() {
    let mut a = String::from("a");
    let closure = || {
        a.push_str("b");
        a
    };

    closure();
}
Run Code Online (Sandbox Code Playgroud)

这让我很困惑.似乎在我打电话的时候closure(),closure如果里面的东西是可变的,就会被借用.我回来后为什么不借用a呢?

Mat*_* M. 11

有3个功能性状的防锈:Fn,FnMutFnOnce.向后走:

  • FnOnce 只保证值可以调用一次,
  • FnMut 只保证在可变的情况下可以调用该值,
  • Fn 保证可以多次调用该值,并且不会发生变化.

闭包将自动实现这些特征,具体取决于它捕获的内容以及它如何使用它.默认情况下,编译器将选择限制性最小的特征; 如此偏爱Fn一遍FnMutFnMut一遍FnOnce.

在你的第二种情况:

let mut a = String::from("a");
let closure = || {
    a.push_str("b");
    a
};
Run Code Online (Sandbox Code Playgroud)

这种关闭需要能够返回a,这需要FnOnce.它a进入捕获.如果你试图第二次调用你的闭包,它将无法编译.如果您尝试访问a,则无法编译.

这就是FnOnce"最后手段"实施的原因.

另一方面,你的第一个案例:

let mut a = String::from("a");
let closure = || {
    a.push_str("b");
};
Run Code Online (Sandbox Code Playgroud)

最多需要一个可变引用a,因此通过可变引用进行捕获.由于它捕获了一个可变引用,因此闭包实现FnMut,因此只有在它本身是可变的时才能被调用.

如果你删除mut,a编译器会向你发出信号,它需要a可变地借用.

closure您尝试调用它之前,编译器不要求它本身可变地声明; 毕竟你可以通过值将它传递给函数而不调用它(你自己),在这种情况下mut将是多余的.

  • @PaulRazvanBerg:可能会,但不需要。这是因为,如果您拥有某物的所有权,则始终可以将其重新绑定到可变绑定。那就是`让a = ...; 让 mut a = a;`。 (3认同)