闭包使局部变量的所有权保持比预期更长的时间
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
实现了 Copy
,var
的值将被复制以用于闭包。
the closure should be over by the time I actually access
没有。 Iterators are lazy。也就是说这里的操作顺序是:
- 我们在组合迭代器上调用
next
。
- 这会在数组的迭代器上调用
next
。重复此步骤,直到条件通过。
- 运行 带有值的循环体。
- 重复整个过程。
您正在过滤器闭包内捕获 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;
}
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
实现了 Copy
,var
的值将被复制以用于闭包。
the closure should be over by the time I actually access
没有。 Iterators are lazy。也就是说这里的操作顺序是:
- 我们在组合迭代器上调用
next
。 - 这会在数组的迭代器上调用
next
。重复此步骤,直到条件通过。 - 运行 带有值的循环体。
- 重复整个过程。
您正在过滤器闭包内捕获 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;
}