不能分配给闭包中使用的变量,因为它是借用的

Nik*_*s R 3 closures rust

我试图通过使用小的辅助闭包使我的代码的某些部分更易于阅读。

fn main() {
    let mut loop_index = 0;

    let get_src_index = || return loop_index % 2;
    let get_dst_index = || return (loop_index + 1) % 2;

    loop_index += 1;
}
Run Code Online (Sandbox Code Playgroud)

还有一些使用get_src_index()and 的闭包get_dst_index(),但它们对问题并不重要。问题是我不能再修改loop_index

fn main() {
    let mut loop_index = 0;

    let get_src_index = || return loop_index % 2;
    let get_dst_index = || return (loop_index + 1) % 2;

    loop_index += 1;
}
Run Code Online (Sandbox Code Playgroud)

我不太明白为什么 Rust 不允许增加loop_index变量。有没有更“生锈”的方式来做到这一点?

She*_*ter 7

正如错误消息所说,您无法更改该值,因为它是借用的。这就像你说的一样:

let mut loop_index = 0;
let foo = &loop_index;
loop_index += 1;
Run Code Online (Sandbox Code Playgroud)

当存在未完成的不可变借用时,您不得修改值。这是 Rust 中的一个基本概念,并支持它提供的安全性。

为什么闭包有对变量的引用?这就是闭包的全部意义——捕捉环境。闭包根据内部发生的操作推断如何捕获变量,在这种情况下,引用就足够了。

这通常是您想要的,因为引用很容易传递。在这种情况下,您有数字,因此没有理由更喜欢参考。我们可以使用move关键字将数字移动闭包中。由于数字实现Copy,这将制作一个副本。然后闭包与现有值完全分离:

let mut loop_index = 0;

let get_src_index = move || loop_index % 2; // No need for `return`
let get_dst_index = move || (loop_index + 1) % 2;

loop_index += 1;
Run Code Online (Sandbox Code Playgroud)

然而,我不认为这些特殊的闭包真的能给你带来任何好处。整数运算通常很便宜,而条件运算通常不那么便宜,因此进行额外的计算可能会更好。


如果您需要能够修改loop_index并在闭包内反映该更改,您可以使用Cell

use std::cell::Cell;

fn main() {
    let mut loop_index = Cell::new(0);

    let get_src_index = || loop_index.get() % 2;
    let get_dst_index = || (loop_index.get() + 1) % 2;

    loop_index.set(loop_index.get() + 1);
}
Run Code Online (Sandbox Code Playgroud)

甚至更好,在很多情况下,你不需要反正维护自己的循环索引。Iterator::enumerate为你照顾它。