尝试理解 Rust 中的可变闭包

Jai*_*lla 10 closures rust

我是一个 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 selfborrows_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);是在您的代码中执行此操作的,它只是不立即显而易见。