我是一个 Rustacean 新手(完成了 rustaling 课程,到目前为止还很享受)。我在 Rust 书中的一些闭包示例中遇到了麻烦。特别是这个:
fn main() {
let mut list = vec![1, 2, 3];
let mut borrows_mutably = || list.push(7);
borrows_mutably();
}
Run Code Online (Sandbox Code Playgroud)
我们需要声明关闭这一事实mut对我来说很难理解。它确实是必要的,因为如果你不将它声明为 mut,编译器会抱怨:
calling `borrows_mutably` requires mutable binding due to mutable borrow of `list`
| |
| help: consider changing this to be mutable: `mut borrows_mutably`
|
| borrows_mutably();
| ^^^^ cannot borrow as mutable
Run Code Online (Sandbox Code Playgroud)
我在这里和那里读过很多帖子,我的理解是闭包需要被定义为mut因为它正在改变它的环境。不知道这个直觉对不对……
不管怎样,在玩另一个闭包时,我发现了一个打破我理解的例子。这个:
calling `borrows_mutably` requires mutable binding due to mutable borrow of `list`
| |
| help: consider changing this to be mutable: `mut borrows_mutably`
|
| borrows_mutably();
| ^^^^ cannot borrow as mutable
Run Code Online (Sandbox Code Playgroud)
我有一个闭包,用于按整数的绝对值对整数列表进行排序并计算发生的操作次数。显然,这种关闭也正在改变它的环境。但在本例中我不需要声明它mut,因为看起来我不是在代码中调用闭包,而是将其传递给另一个函数 ( sort_by_key),而该函数又会调用它。为什么会有这种行为?
我觉得这非常令人困惑。事实上,如果sort_by_key我不将函数传递给直接调用它,我会得到相同的错误 ( cannot borrow func as mutable...)。
cdh*_*wie 11
我在这里和那里读过很多帖子,我的理解是,需要将闭包定义为
mut因为它正在改变其环境。不知道这个直觉对不对……
是的,这是正确的。在幕后,闭包值捕获对 的可变引用list。换句话说,该borrows_mutably值包含 a&mut Vec<_>并且是通过该引用Vec::push来调用的。
那么为什么borrows_mutably需要声明mut呢?首先,请注意,通过共享引用访问可变引用不允许可变访问。这就是为什么闭包的调用签名FnMut采用&mut self- 如果采用&self,则&mut会位于 a 后面&,并且& &mut行为与 相同& &。因为FnMut调用必须采取&mut self,borrows_mutably需要声明mut。
但在本例中我不需要声明它
mut,因为看起来我不是在代码中调用闭包,而是将其传递给另一个函数 (sort_by_key),而该函数又会调用它。
可变性是绑定的属性,而不是值的属性。如果您采用不可变绑定并将其分配给可变绑定,则可以更改它。
例如,这无法编译:
let foo = vec![1];
foo.push(2);
Run Code Online (Sandbox Code Playgroud)
但这确实可以编译!
let foo = vec![1];
let mut foo2 = foo;
foo2.push(2);
Run Code Online (Sandbox Code Playgroud)
我们只是将值移入foo不同的可变绑定中。现在我们可以改变它。
同样的事情也发生在sort_by_key,只不过它被函数调用混淆了。当你将闭包传递给这个函数时,你就放弃了它。 该函数在可变绑定中sort_by_key接收此参数,现在可以在其中调用它:
pub fn sort_by_key<K, F>(&mut self, mut f: F)
// ^^^
Run Code Online (Sandbox Code Playgroud)
请注意, 的可变性f不是函数签名的一部分,这就是它没有出现在文档中的原因。参数的可变性是函数私有的细节——函数是否计划改变给定的任何值与调用者无关。
澄清一下,FnMut闭包值可以存储在不可变绑定中,但不能从那里调用。需要将其移至可变绑定中才能调用。该行list.sort_by_key(func);是在您的代码中执行此操作的,它只是不立即显而易见。