It seems that if you borrow a reference to a struct field, the whole struct is considered borrowed. I've managed to isolate and example of what I want to do. I just want to get a "read-only" reference to a field in B
to obtain some data and then modify another field of B
. Is there a idiomatic Rust way to do this?
struct A {
i: i32,
}
struct B {
j: i32,
a: Box<A>,
}
impl B {
fn get<'a>(&'a mut self) -> &'a A {
&*self.a
}
fn set(&mut self, j: i32) {
self.j = j
}
}
fn foo(a: &A) -> i32 {
a.i + 1
}
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let a_ref = b.get();
b.set(foo(a_ref));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> src/main.rs:27:5
|
26 | let a_ref = b.get();
| - first mutable borrow occurs here
27 | b.set(foo(a_ref));
| ^ second mutable borrow occurs here
28 | }
| - first borrow ends here
It's a feature of the language. From the compiler point of view, there is no way for it to know that it's safe to call your
set()
function whilea
is borrowed viaget()
.Your
get()
function borrowsb
mutably, and returns a reference, thusb
will remain borrowed until this reference goes out of scope.You have several way of handling this:
Separate your two fields into two different structs
Move the code which needs to access both attribute inside a method of
B
Make your attributes public, you will thus be able to directly get references to them
Compute the new value before setting it, like this:
Expanding a bit on Levans' answer
That might look like this at a first pass:
However, this hard-codes the call to
foo
. You could also accept a closure to allow this to be more flexible:This is also applicable when you have borrowed two disjoint subsets of attributes. For example:
Can be changed into
You can combine these two steps (and I'd say that it's better practice) and move the method onto the inner struct.