为什么将值移到闭包中仍会显示错误消息“无法借用可变的不可变局部变量”?

时间:2018-10-28 08:23:09

标签: rust

在下面的代码中,我明确地将name函数中的main移到了闭包中,一切正常:

fn main() {
    let name = String::from("Alice");

    let welcome = || {
        let mut name = name;
        name += " and Bob";
        println!("Welcome, {}", name);
    };

    welcome();
}

我本以为在闭包的开头添加一个move会完成同样的事情,并导致值被移动并创建一个FnOnce

fn main() {
    let name = String::from("Alice");

    let welcome = move || {
        name += " and Bob";
        println!("Welcome, {}", name);
    };

    welcome();
}

但是,我收到了错误消息:

error[E0596]: cannot borrow immutable local variable `welcome` as mutable
 --> main.rs:9:5
  |
4 |     let welcome = move || {
  |         ------- help: make this binding mutable: `mut welcome`
...
9 |     welcome();
  |     ^^^^^^^ cannot borrow mutably

error[E0596]: cannot borrow captured outer variable in an `FnMut` closure as mutable
 --> main.rs:5:9
  |
5 |         name += " and Bob";
  |         ^^^^

在这种情况下,在闭包上思考move的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

  

我本以为在闭包的开头添加一个move会完成相同的事情,……

类似的事情。您只是忘记声明namewelcome为可变。这段代码可以正常工作:

fn main() {
    let mut name = String::from("Alice");

    let mut welcome = move || {
        name += " and Bob";
        println!("Welcome, {}", name);
    };

    welcome();
}

闭包的两个版本都将name移到闭包中。在第一个版本中,这是由闭包内部的name消耗引起的。第二个版本不使用name,而是使用move关键字来强制移动。

  

…并导致值被移动并创建FnOnce

将值移动到闭包中并不会使其变为FnOnce。如果闭包使用捕获的值,则它变成FnOnce,因为它显然只能执行一次。因此,闭包的第一个版本为FnOnce,因为它消耗name。上面的Clousre是FnMut,可以多次调用。两次调用都会导致输出

Welcome, Alice and Bob
Welcome, Alice and Bob and Bob

(我在上面稍加草率地使用了函数特征名称。实际上,每个闭包均实现FnOnce,因为每个闭包至少可以调用一次。某些闭包可以多次调用。 ,因此它们另外是FnMut。某些可以多次调用的闭包不会改变其捕获状态,因此除了其他两个特征之外,它们也是Fn。)