在下面的代码中,我明确地将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
的正确方法是什么?
答案 0 :(得分:3)
我本以为在闭包的开头添加一个
move
会完成相同的事情,……
类似的事情。您只是忘记声明name
和welcome
为可变。这段代码可以正常工作:
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
。)