I have a mutable struct and a meta-struct that holds &mut ref to the first one. When I pass the latter to a non-mutable method with owned output (generate_items), the borrow checker thinks the passed struct gets borrowed and forbids the other borrowing call (insert_items).
struct Calculator { pub cell: usize }
struct MetaCalc<'a> { calc: &'a mut Calculator }
struct Storage { pub data: usize }
impl<'a> Storage {
fn generate_items(&self, input: &usize, meta: &'a mut MetaCalc<'a>) -> Vec<usize> {
println!("input: {input}");
vec![987, 654, 321]
}
fn insert_items(&mut self, input: &Vec<usize>, meta: &'a mut MetaCalc<'a>) {
for i in input {
self.data += *i;
}
}
}
fn main() {
let mut calc = Calculator { cell: 1 };
let mut meta = MetaCalc { calc: &mut calc };
let mut st = Storage { data: 345 };
let items = st.generate_items(&987, &mut meta);
// ^^^^^^^^
// borrow checker thinks `meta` gets borrowed here and remains so
st.insert_items(&items, &mut meta);
// BC complains of this call ^^
// other structs will use `items`
}
Why? In generate_items, nothing is borrowed -- the output struct is owned, and has no lifetimes with it.
If I remove &mut Calc member from struct Meta and pass it along with other params, the code compiles fine. But it becomes a big pain to work with -- couple of dozen of test calls like this are irritating.
Still, if I make Meta a mutable param (even if it's detached from Calculator), it again becomes "borrowed" and stops to compile.
I thought, it might be because lifetime 'a is shared among two params, but introducing another lifetime won't work, because it's not constrained by anything.
(temporarily unchecked the solution, will put back)
Follow-up question: is there a sane way to have a trait with associated type and avoid this pitfall?
I tried wrapping the assoc.type into another struct, but it same way fall into this trap of 'a Type<'a>. I tried adding another lifetime, but compiler won't allow this, because the new lifetime becomes unconstrained.
Or am I running into some fundamental limitation of traits?
Why would this be related to traits? It's purely a lifetime error. You still got the literal &'a mut T<'a> anti-pattern, which won't compile regardless of any traits.