I have a struct containing two fields and I want to modify one field (mutable borrow) using another field (immutable borrow), but I get an error from the borrow checker.
For instance, the following code:
struct Struct {
field1: Vec<i32>,
field2: Vec<i32>,
}
fn main() {
let mut strct = Struct {
field1: vec![1, 2, 3],
field2: vec![2, 3, 4],
};
strct.field1.retain(|v| !strct.field2.contains(v));
println!("{:?}", strct.field1);
}
gives the following error:
error[E0502]: cannot borrow `strct` as immutable because `strct.field1` is also borrowed as mutable
--> src/main.rs:12:25
|
12 | strct.field1.retain(|v| !strct.field2.contains(v));
| ------------ ^^^ ----- - mutable borrow ends here
| | | |
| | | borrow occurs due to use of `strct` in closure
| | immutable borrow occurs here
| mutable borrow occurs here
What are the Rust ways of updating one field using another from within a closure?
Usually the borrow checker can distinguish between the different fields of a structure, but this doesn't work within closures (lambdas).
Instead, borrow the second field outside the closure:
This recent blog post shows a very useful pattern for this kind of problem:
In other words, the borrows are defined right with the closure and moved into the closure. This makes it totally clear that their purpose is to provide the closure with borrowed values. In context of the original question the pattern would look like this:
A nice property of this code is that the borrow of
field2
does not stick around after it is no longer used.