Lifetimes with nested struct pointing to parent

I'm trying to understand why this doesn't compile and how to overcome the problem. This is a more or less distilled version of my actual code. Here i'm having an Elem that holds a reference to an item in Container. The container is stored in Root and is manipulated by it. Elem can't ever outlive the container, but I can't seem to prove that to the compiler.

The immediate issue is that I can't run the set function twice.

I have tried to remove the constraint in the set function, but then the compiler returns an error, that self doesn't live as long as its type, which doesn't make much sense to me.

Thanx.

struct Elem<'a> {
    num: &'a u32
}

impl<'a> Elem<'a> {
    fn new(num: &'a u32) -> Self {
        Self { num }
    }
}

struct Container<'a> {
    num: u32,
    elem: Option<Elem<'a>>
}

impl<'a> Container<'a> {
    fn new() -> Self {
        Self {
            num: 0,
            elem: None,
        }
    }

    fn set(&'a mut self, num: u32) {
        self.num = num;

        self.elem = Some(Elem::new(&self.num));
    }
}

struct Root<'a> {
    cnt: Container<'a>
}

impl<'a> Root<'a> {
    fn new () -> Self {
        Self { cnt: Container::new() }
    }

    fn set(&'a mut self, num: u32)  {
        self.cnt.set(num);
        self.cnt.set(num);
    }
}

fn main() {
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `self.cnt` as mutable more than once at a time
  --> src/lib.rs:42:9
   |
35 | impl<'a> Root<'a> {
   |      -- lifetime `'a` defined here
...
41 |         self.cnt.set(num);
   |         -----------------
   |         |
   |         first mutable borrow occurs here
   |         argument requires that `self.cnt` is borrowed for `'a`
42 |         self.cnt.set(num);
   |         ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` due to previous error

What you are attempting to define as Container is a “self-referential struct”, which is not natively supported by Rust.

The immediate reason you get errors is that when you write struct Container<'a> {, one of the things implied by that is that 'a is some lifetime that outlives the Container. Hence, anything inside the Container cannot be borrowed for 'a (except in the degenerate case where 'a is exactly as long as the Container exists and the Container is borrowed “for the rest of its life”, which is why you find that you can't run set twice — the &'a mut self parameter is borrowing it for 'a).

Generally, best practice is to design data structures differently. If a self-reference is really necessary, you can use ouroboros which uses macros and unsafe code to synthesize a 'this lifetime that can be used to borrow other fields. However, this has some performance cost (the borrowed data must be boxed), complicated API, and other restrictions (and the risk of this technique being found to be unsound), so you should not do it unless there is no alternative (usually because some other library you are using provides only a borrowing type and not an owning one).

I find myself running into this problem quite often. Sometimes it's because of other modules which have data types in their API which have a lifetime annotation and you want to store those data types along with the values they refer to in the same struct.

I found that to avoid this problem (from the p.o.v. of an API provider), it sometimes makes sense to use Arc (or Weak) (to eliminate lifetime annotations) instead of keeping references around.

See also modified Playground, which avoids cloning the u32 and instead keeps two Arcs pointing to the same u32. (Of course in this example, you'd rather copy the integer, but depending on your use case, you might adopt the idea or do something similar.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.