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

时间:2018-04-23 17:25:12

标签: rust

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

    closure();
}

这不会编译:

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

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

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

    closure();
}

这让我很困惑。似乎当我打电话给closure()时,如果内部有可变的东西,closure将被借用。当我返回a时,为什么不借用它?

1 个答案:

答案 0 :(得分:10)

Rust中有3个功能特征:FnFnMutFnOnce。向后走:

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

封闭将automatically implement这些特征,具体取决于它捕获的内容以及它如何使用它。默认情况下,编译器将选择最少限制性特征;因此Fn优先于FnMutFnMut优先于FnOnce

在你的第二个案例中:

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

此闭包需要能够返回a,这需要FnOnce。它将a移动到捕获中。如果你试图第二次调用你的闭包,它将无法编译。如果您尝试访问a,则无法编译。

这就是为什么FnOnce是"最后的手段"实施

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

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

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

如果您在mut前删除a,编译器会发信号通知您需要可变地借用a

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