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
时,为什么不借用它?
答案 0 :(得分:10)
Rust中有3个功能特征:Fn
,FnMut
和FnOnce
。向后走:
FnOnce
仅保证可以调用一次值,FnMut
仅保证在可变的情况下可以调用该值Fn
保证可以多次调用该值,并且不会发生变化。封闭将automatically implement这些特征,具体取决于它捕获的内容以及它如何使用它。默认情况下,编译器将选择最少限制性特征;因此Fn
优先于FnMut
而FnMut
优先于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
将是多余的。