闭包使局部变量的所有权保持比预期更长的时间

Closures keep ownership of local variables for longer than expected

let array = [40];
let mut var = 60;

for element in array.iter().filter(|&x| {*x < var}) {
    var += 1; // Error
}

var += 1; // Fine again

对我来说,这段代码似乎完全合法,因为当我在它之外实际访问 var 时闭包应该已经结束。

error[E0506]: cannot assign to `var` because it is borrowed
 --> src/main.rs:6:9
  |
5 |     for element in array.iter().filter(|&x| {*x < var}) {
  |                                        ---- borrow of `var` occurs here
6 |         var += 1; // Error
  |         ^^^^^^^^ assignment to borrowed `var` occurs here

为什么在调用var += 1时仍然借用了var,尽管闭包的范围应该已经结束了?需要结果才能达到 var += 1。虽然在没有 filter 的情况下也可以做这样的事情,但它会导致我的代码不那么清晰,所以我想继续使用它。

Shepmaster 的回答是正确的(我不知道迭代器是 那个 懒惰的),但是如果你不想 var 检查(即 filter 条件)在循环中改变,你可以使用 move closure:

filter(move |&x| *x < var)

由于 i32 实现了 Copyvar 的值将被复制以用于闭包。

the closure should be over by the time I actually access

没有。 Iterators are lazy。也就是说这里的操作顺序是:

  1. 我们在组合迭代器上调用 next
  2. 这会在数组的迭代器上调用 next。重复此步骤,直到条件通过。
  3. 运行 带有值的循环体。
  4. 重复整个过程。

您正在过滤器闭包内捕获 val。您还尝试在循环中修改它。这意味着必须同时存在可变引用和不可变引用,这是不允许的。

您可以使用 Cell 来获得内部可变性:

use std::cell::Cell;

fn main() {
    let array = [40];
    let var = Cell::new(60);

    for element in array.iter().filter(|&&x| x < var.get()) {
        var.set(var.get() + 1);
    }

    let mut var = var.get();
    var += 1;
}