por*_*ton 0 closures mutable rust borrowing
考虑以下(人为的)递增x方式9。
fn main() {
let mut x = 0;
let mut f = || {
x += 4;
};
let _g = || {
f();
x += 5;
};
}
Run Code Online (Sandbox Code Playgroud)
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> x.rs:6:12
|
3 | let mut f = || {
| -- first mutable borrow occurs here
4 | x += 4;
| - first borrow occurs due to use of `x` in closure
5 | };
6 | let _g = || {
| ^^ second mutable borrow occurs here
7 | f();
| - first borrow later captured here by closure
8 | x += 5;
| - second borrow occurs due to use of `x` in closure
error: aborting due to previous error
For more information about this error, try `rustc --explain E0499`.
Run Code Online (Sandbox Code Playgroud)
所以,它不起作用。如何制作像上面这样的算法来修改闭包中的变量并从中调用另一个也修改变量的闭包?
在传统语言中,这很容易。在 Rust 中做什么?
根据设计,闭包必须包含在创建时使用的外部对象,在我们的例子中,闭包必须借用外部x对象。因此,正如编译器向您解释的那样,在创建闭包时,f它可变地借用它x,并且在创建闭包时您不能再次借用它g。
为了编译它,您不能包含任何要更改的外部对象。相反,您可以直接将对象作为闭包的参数传递(可以说它更具可读性)。通过这种方式,您可以描述闭包接受某种类型的对象,但您尚未使用/传递任何实际对象。仅当您调用闭包时才会借用该对象。
fn main() {
let mut x = 0;
let f = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
*local_x += 4;
};
let _g = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
f(local_x);
*local_x += 5;
};
_g(&mut x); // finally we borrow `x`, and this borrow will later move to `f`,
// so no simultaneous borrowing.
println!("{}", x); // 9
}
Run Code Online (Sandbox Code Playgroud)
公认的答案是最惯用的方法,但还有一种替代方法在附加参数不起作用的情况下很有用,例如,当您需要将闭包传递给第三方代码时,该代码将在没有参数的情况下调用它。在这种情况下,您可以使用 a Cell,一种内部可变性形式:
use std::cell::Cell;
fn main() {
let x = Cell::new(0);
let f = || {
x.set(x.get() + 4);
};
let g = || {
f();
x.set(x.get() + 5);
};
f();
g();
assert_eq!(x.get(), 13);
}
Run Code Online (Sandbox Code Playgroud)