在下面的代码中,我明确地强制将namefrommain函数移动到闭包中,并且一切正常:
fn main() {
let name = String::from("Alice");
let welcome = || {
let mut name = name;
name += " and Bob";
println!("Welcome, {}", name);
};
welcome();
}
Run Code Online (Sandbox Code Playgroud)
我原以为move在闭包的开头添加 a会完成同样的事情,并导致值被移动并创建 a FnOnce:
fn main() {
let name = String::from("Alice");
let welcome = move || {
name += " and Bob";
println!("Welcome, {}", name);
};
welcome();
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到了错误消息:
fn main() {
let name = String::from("Alice");
let welcome = || {
let mut name = name;
name += " and Bob";
println!("Welcome, {}", name);
};
welcome();
}
Run Code Online (Sandbox Code Playgroud)
move在这种情况下,考虑闭包的正确方法是什么?
我原以为
move在闭包的开头添加 a会完成同样的事情,......
它做同样的事情。您只是忘记声明name和welcome为可变的。这段代码工作正常:
fn main() {
let mut name = String::from("Alice");
let mut welcome = move || {
name += " and Bob";
println!("Welcome, {}", name);
};
welcome();
}
Run Code Online (Sandbox Code Playgroud)
两个版本的闭包都name被移到了闭包中。在第一个版本中,这是由name闭包内部的消费隐式引起的。第二个版本不消耗name,而是使用move关键字来强制移动。
...并导致值被移动并创建一个
FnOnce.
将值移动到闭包中并不能使它成为FnOnce。如果一个闭包消耗了一个捕获的值,它就会变成FnOnce,因为它显然只能这样做一次。因此,闭包的第一个版本是FnOnce,因为它消耗name。上面的 clousre 是FnMut,并且可以被多次调用。调用它两次导致输出
fn main() {
let mut name = String::from("Alice");
let mut welcome = move || {
name += " and Bob";
println!("Welcome, {}", name);
};
welcome();
}
Run Code Online (Sandbox Code Playgroud)
(我上面有点草率地使用了函数 trait 名称。实际上,每个闭包都实现了FnOnce,因为每个闭包至少可以被调用一次。有些闭包可以被多次调用,所以它们是FnMut额外的。还有一些可以被多次调用的闭包时间不会改变他们被捕获的状态,所以他们是Fn对其他两个特征的补充。)