I have some structs containing some data that look like this:
struct A {
// Some data
}
struct B<'s> {
a: &'s mut A
c: C<'s>
}
impl<'s> B<'s> {
fn new(a: &'s mut A, d: &'s D) -> B<'s> {
let c = C::new(d);
B { a, c }
}
fn extract_c(self) -> C<'s> {
self.c
}
}
// A smart pointer provided by a library
struct C<'s> {
d: &'s D,
// Other fields holding some data, not referencing A
}
struct D {
// Some other data not referencing A in any way (provided by a library)
}
I also have functions that that create and modify said structs like this:
fn modify(b: &mut B) {
// Modifies b.a and b.c
}
fn construct_c<'s>(a: &'s mut A, d: &'s D) -> C<'s> {
let mut b = B::new(a, d); // C is created in B::new
modify(&mut b);
b.extract_c()
}
I want to use construct_c somewhere else such that I can make another reference to A after obtaining the result from the call, like this:
fn main() {
let mut a = A::new();
let d = D::new();
let c = construct_c(&mut a, &d); // First mutable borrow of `a`
println!("{a}"); // Second borrow of `a`
let result = do_sth_with_c(c); // Move of `c`
do_sth_with_a(a);
// Some other code...
}
However, when I try to do that, the compiler says that when I call do_sth_with_c, I am using the first mutable borrow of a, even though c doesn't hold the reference to a provided to construct_c.
When I removed println!("{a}"); and do_sth_with_a the code compiles, but I really need to print that information and do it before calling do_sth_with_c. Is there a way to tell the compiler that C knows nothing about the reference to a and that it is safe to make new references after calling construct_c?
EDIT 1:
When I substituted all the references &mut A with Rc<RefCell<A>> the code compiles. But is there another way without using Rc and RefCell?
EDIT 2:
Following this answer, introducing another lifetime to B seems to resolve the issue.
How B changed:
struct B<'a, 's> {
a: &'a mut A,
c: C<'s>,
}
// All functions that use `B` need to be updated as well
You wrote in a comment about
C, "some other data not referencingAin any way". But by using the same lifetime you're telling the compiler that they are related. So, change your definitions fromto
Now each lifetime can vary independently, and in particular, the
'clifetime is allowed to be longer than's.That said, I have to warn you that you may be trying to use references where owned data would be better. A common beginner mistake is to try to build data storage structures out of references, and this is usually not a good idea because it either turns out impossible, or highly constrains how the structure can be used.