Reputation: 11
I have two closure that reference and modify an outer variable.
let mut i: i32 = 0;
let mut add = || {
i += 1;
};
let mut sub = || {
i -= 1;
};
add();
sub();
The following code won't compile that produces the error below:
error[E0499]: cannot borrow `i` as mutable more than once at a time
--> src/main.rs:14:19
|
11 | let mut add = || {
| -- first mutable borrow occurs here
12 | i += 1;
| - first borrow occurs due to use of `i` in closure
13 | };
14 | let mut sub = || {
| ^^ second mutable borrow occurs here
15 | i -= 1;
| - second borrow occurs due to use of `i` in closure
16 | };
17 | add();
| --- first borrow later used here
How to use mutable borrow in multiple closures?
Upvotes: 0
Views: 85
Reputation: 307
restructuring your code a little bit it works!
fn main() {
let mut i: i32 = 0;
let add = |mut j| {
j += 1;
j
};
let sub = |mut j| {
j -= 1;
j
};
i = add(i);
i = sub(i);
println!("{}", i); // 0
}
Upvotes: -1
Reputation: 16535
The way you described it, you can't. The add
-closure takes an exclusive ("mutable") borrow of i
at the point where the closure is constructed. The compiler guarantees that add
is the only way to observe i
until that borrow ends. Yet sub
does exactly the same thing: It tries to borrow i
exclusively, and that borrow is used after the call to add()
. But there is no way that both
add
has exclusive access to i
via it's mutable borrowsub
has an exclusive borrow of i
, which is exclusive while add
is being called, so it can be used by sub
after add
has been calledcan be true at the same time.
Depending on your use-case, and if you can't avoid this problem altogether, either restructure your code:
fn main() {
let mut i: i32 = 0;
let mut add = || {
i += 1;
};
add();
// The mutable borrow by `add` has ended, so `i` is free to get borrowed again
let mut sub = || {
i -= 1;
};
sub();
}
or use a RefCell
to avoid having to use mutable borrows:
use std::cell::RefCell;
fn main() {
let i: RefCell<i32> = RefCell::new(0);
let add = || {
*i.borrow_mut() += 1;
};
let sub = || {
*i.borrow_mut() -= 1;
};
add(); // 1
sub(); // 0
add(); // 1
add(); // 2
assert_eq!(*i.borrow(), 2);
}
Notice that by using a RefCell
, the bindings add
/sub
are no longer declared mut
, as the closures use immutable ("shared") borrows of i
; there is a runtime-check embedded in RefCell
that checks if i
is in fact exclusively borrowed while the closures execute. For instance, it is conceivable that sub
calls add
while it is executing, leading to a situation that is statically guarantee to not occur in the code you pasted: Two aliasing + mutable access paths to the same variable; as written above, RefCell
would panic!
to guarantee at runtime that this does not occur.
Upvotes: 0