Lifetime inference problem

I have reduced my issue down to the minimal example below. This code currently gives a lifetime inference error. I understand why (I think) because it doesn't know if variable will live long enough to go inside inner.vector. But I can't seem to figure out how to fix it. As far as I know, I am not doing anything invalid here. I want the lifetime of variable to be tied to the inner struct, so that Outer can put it in vector.

playground link

struct Outer<'a> {
    vector: Vec<&'a str>,
    inner: Inner,
}

struct Inner {}

impl<'a> Inner {
    fn get(&'a self, _x: &str) -> &'a str {
        // implementation not shown
        "bar"
    }
}

impl<'a, 'b> Outer<'a> {
    fn infer_lifetime_problem(&mut self, x: &str) {
        let variable = self.inner.get(x);
        self.vector.push(variable);
    }

    fn mut_borrow(&mut self, x: &str) {
        self.infer_lifetime_problem(x)
    }

    fn borrow(&self, x: &str) {}

    fn borrow_checker_problem(&mut self, x: &str) {
        if x.len() > 3 {
            self.mut_borrow(x);
        }
        self.borrow(x)
    }
}

fn main() {
    let mut my_struct = Outer {
        vector: vec![],
        inner: Inner {},
    };

    my_struct.borrow_checker_problem("foo");
}

It looks like you're trying to create a self-referential struct here. Those are not generally allowed in Rust. You can either modify your program to have Outer store indices instead of references into Inner, or you can use the self-referential arena trick.

5 Likes

Either your trying to do self-referential structs or you got your lifetime annotations wrong. You might want to give us more details on the Inner type and the get method. If it really returns some reference into the Inner value itself, then - yes - your trying to create a self-referential struct, in which case you might want to give some more information anyways on what you're actually trying to do achieve with this Outer and Inner type, at least if you need help to decide what the best alternative approach is.

1 Like

I am indeed trying to make a self-referential arena. Thank you for your link @Kestrer , I will look at that and see how to apply their "trick". Hopefully that can resolve this issue.

So it looks like this is not possible in safe-code without interior mutability. Even when I take this example from the article @Kestrer shared and try and create a self-referential struct like this:

struct Test<'arena> {
    vec: Vec<PersonRef<'arena>>,
    arena: Arena<'arena>,
}

I still have the same fundamental problem. The only way around it that I can see is interior mutability or unsafe code to get around the borrow checker.

Look, just don't write self-referential structs. Use indexes or clone them or use an Rc or something like that.