Object lifetime

I would like to store the reference to an object within the object itself. Using Arc is too much heavy lifting for my use-case. And as far as I know annotating Composite with 'object lifetime will just make it spread, but I don't really want the user of my API to deal with lifetime, it's an implementation detail and not necessary to expose to the user. Is there some good way to express what I want without spreading lifetime annotations everywhere?

pub struct Member<'object, T : 'object>
{
    value: T,
    parent: Option<&'object Composite>,
}

impl<'object, T : 'object> Member<'object, T>
{
    pub fn new(value: T) -> Member<'object, T>
    {
        Member {value, parent: None}
    }
}

pub struct Composite
{
    member: Member<'static, usize>,
}

impl Composite
{
    pub fn new(value: usize) -> Composite
    {
        Composite { member: Member::new(value) } 
    }
    
    pub fn set_parent<'object>(&'object mut self)
    {
        self.member.parent = Some(self);
    }
}

fn main() 
{
    let item: Composite = Composite::new(1);
    item.set_parent();
}

(Playground)

You will not use Arc unless you are doing multithreading. You should use Rc<T> if you are using the T in one thread.

I did not understand you. 'object is not a special lifetime like 'static. It don't have any special meaning. It is like 'a.

Lifetime annotations in rust are a part of function and struct signatures, it is not an implementation detail. Users needs to know the lifetime like they need to know the parameter types of functions.

But you may want to eliminate the lifetimes in public API, if possible. But don't make this the primary target.

It seems like there is not even a way of creating circular reference as you want by using borrows. See this:

Nonetheless I converted your code to this, I think it is simpler (It don't works because of the reasons above):

pub struct Member<'a, T: 'a>
{
    value: T,
    parent: Option<&'a Composite>,
}

impl<'a, T: 'a> Member<'a, T>
{
    pub fn new(value: T) -> Self
    {
        Self {value, parent: None}
    }
}

pub struct Composite
{
    member: Member<'static, usize>,
}

impl Composite
{
    pub fn new(value: usize) -> Self
    {
        let mut s = Self { member: Member::new(value) };
        let parent = Some(&s);
        s.member.parent = parent;
        s
    }
}

fn main() 
{
    let _item = Composite::new(1);
}
1 Like

As @eko noted, this is not possible in safe Rust, and is usually more trouble than it's worth. Consider redesigning your code to avoid this kind of self-referential condition.

If your struct has a lifetime parameter, that lifetime parameter refers to data that's stored elsewhere, outside the struct, and which must exist for your struct to be valid. See this post from @alice:

If you want your struct to refer to non-owned data without an explicit lifetime, shared ownership (Rc or Arc) is the canonical solution, and may cost less than you think (a handful of integer comparisons and increments/decrements, basically).