I'm aware it is not much possible nor recommended to have both a field that owns a value, and another one that stores a reference to the same value in a struct.
I was experimenting a bit with a more elaborate case, and stumbled on what seems to be an equivalent problem. I tried my best to "beat" the borrow checker but even when I'm feeling like I have a solution, an error still rises that I do not fully understand.
The idea is I want to have a struct A that stores both an owned value of type C, and a value of type B, with B storing a reference to the field of type C in A:
struct C {}
struct B<'a> {
c: &'a C,
}
struct A<'a> {
b: B<'a>,
c: C,
}
1st question:
I am still somewhat convinced that this should work as if we can prove (using explicit lifetimes) that A.c (so A) outlives B.c, we are good. As it is written: a struct B must not outlive its field B.c, which in turn makes it that A must not outlive it either. If B.c is set to a ref to A.c, then shouldn't all lifetimes be equal?
2nd question:
The more elaborate case I was talking about is that A.b actually stores a Box<dyn MyTrait>, and B now implements this trait. I don't know if that actually plays a big role there, but this definitely adds some troubles with 'static lifetimes.
Below, I tried to be as explicit as possible with the lifetimes, and I still get the error '`instance.c` does not live long enough'. I can't understand why, because lifetimes seem to resolve correctly in my head.
Note that the PhantomData is not needed to get the same error, as pointed by @kmdreko, and was an attempt to show the relation between 'a and 'b.
struct C<'b> {
_p: PhantomData<&'b ()>,
}
struct B<'a, 'b> {
c: &'a C<'b>,
}
trait BTrait {}
impl<'a, 'b> BTrait for B<'a, 'b> {}
struct Dummy {}
impl BTrait for Dummy {}
struct A<'a, 'b> where 'b: 'a {
b: Box<dyn BTrait + 'a>,
c: C<'b>,
}
fn main() {
let c = C { _p: PhantomData };
let dummy = Box::new(Dummy {});
let mut instance = A {
b: dummy,
c,
};
let b = Box::new(B { c: &instance.c });
instance.b = b;
}
Again, as I understand, &instance.c should live as long as instance lives. (削除) Plus C will at least live . Actually C lives at most 'b, so it enforces nothing with respect to 'a.'b, which outlives 'a so B and its stored reference should always be valid. (削除ここまで)
1 Answer 1
In your code, you have actually successfully created a self-referential data structure. I say that because if b were a bit different, you could get it to point to c in a similar way. This code compiles:
struct C {}
struct A<'a> {
b: Option<&'a C>,
c: C,
}
fn main() {
let mut instance = A {
b: None,
c: C {},
};
instance.b = Some(&instance.c);
}
The reason the compiler rejects your code is because dyn Trait is opaque to the compiler. In particular, it cannot assume what it does when dropped. The field b will not be dropped until after its parent A is dropped, but you've tongue-tied the compiler that b may hold a reference to A (to access c). So b will have access to a dangling reference when dropped, which is obviously not allowed.
'b" - By construction, aC<'b>cannot live longer than'b. But the point seems moot to me anyway since'bis not necessary to get the same error: playground