When writing Rust, I often encounter a similar issue that leads to compilation errors, specifically mutable borrow conflicts (E0502). I have simplified it into the following form:
pub struct Foo{
// omits fields
}
impl Foo {
fn get_val(&self, idx: usize) -> usize {
todo!()
}
}
pub struct Bar{
// omits fields
}
pub struct Baz{
foo: Vec<Foo>,
bar: Bar
}
impl Baz{
fn get_foo(&self, idx: usize)->&Foo {
todo!()
}
fn bar_insert(&mut self, val: usize) -> usize{
// use &mut self.bar
todo!()
}
fn some_op(&self, foo: &Foo, val: usize){
todo!()
}
pub fn insert(&mut self, idx: usize){
let foo = self.get_foo(idx); // line 1
let val = foo.get_val(idx); // line 2
let val2 = self.bar_insert(val); // line 3
self.some_op(foo, val2); // line 4
}
}
Suppose this is a lib code, and the ultimate goal is to provide users the ability to insert a piece of data using Baz::insert. Baz consists of data of two types, Foo and Bar. The code will compile with error E0502 because the insert method borrows self immutably in the 1st line, and the borrow’s lifetime lasts until the end of the method. Meanwhile, in the 3rd line, self is borrowed mutably, causing a conflict.
However, I know that bar_insert only modifies the bar field and does not affect foo in any way.
In this case, the 4th line cannot be moved up because the some_op method depends on the value returned in the previous step.
My questions:
Does this compilation error genuinely reflect some design flaw in my code, or is it a limitation of Rust’s current state?
Is there a general approach to solve such problems?
Previously, in such situations, I have either used unsafe raw pointers, RefCell, or clone, but none of these seem like the most appropriate solution.