Why can't I store a value and a reference to that value in the s

ghz 7months ago ⋅ 79 views

Why can't I store a value and a reference to that value in the same struct?

I have a value and I want to store that value and a reference to something inside that value in my own type:

struct Thing {
    count: u32,
}

struct Combined<'a>(Thing, &'a u32);

fn make_combined<'a>() -> Combined<'a> {
    let thing = Thing { count: 42 };

    Combined(thing, &thing.count)
}

Sometimes, I have a value and I want to store that value and a reference to that value in the same structure:

struct Combined<'a>(Thing, &'a Thing);

fn make_combined<'a>() -> Combined<'a> {
    let thing = Thing::new();

    Combined(thing, &thing)
}

Sometimes, I'm not even taking a reference of the value and I get the same error:

struct Combined<'a>(Parent, Child<'a>);

fn make_combined<'a>() -> Combined<'a> {
    let parent = Parent::new();
    let child = parent.child();

    Combined(parent, child)
}

In each of these cases, I get an error that one of the values "does not live long enough". What does this error mean?

Answers

The error message "does not live long enough" indicates that the compiler cannot guarantee that a reference will remain valid for the entire lifetime it is supposed to be used.

Let's break down each case:

Case 1: Storing a Value and a Reference to Something Inside That Value

struct Combined<'a>(Thing, &'a u32);

fn make_combined<'a>() -> Combined<'a> {
    let thing = Thing { count: 42 };
    Combined(thing, &thing.count)
}

In this case, you're trying to store a reference to thing.count in the Combined struct. However, thing is created locally within the make_combined function, and its lifetime is limited to the scope of that function. When you try to return a reference to thing.count, Rust detects that you're trying to return a reference to data that will be dropped at the end of the function, leading to a lifetime error.

Case 2: Storing a Value and a Reference to the Entire Value

struct Combined<'a>(Thing, &'a Thing);

fn make_combined<'a>() -> Combined<'a> {
    let thing = Thing::new();
    Combined(thing, &thing)
}

Similarly, in this case, you're trying to store a reference to thing itself. Again, thing is created locally within the make_combined function, so its lifetime is limited to that function. Returning a reference to thing leads to the same lifetime error as in Case 1.

Case 3: Storing a Value and a Reference to a Value Created in Another Function

struct Combined<'a>(Parent, Child<'a>);

fn make_combined<'a>() -> Combined<'a> {
    let parent = Parent::new();
    let child = parent.child();
    Combined(parent, child)
}

In this case, you're trying to store a reference to child, which is created within the parent.child() function. The error occurs because Rust cannot guarantee that the reference to child will remain valid after the function returns. The lifetime of child is tied to the lifetime of parent, but the compiler cannot infer that from the code alone.

Conclusion

In all cases, the error occurs because you're trying to store references with lifetimes that Rust cannot statically verify to be valid. To resolve these errors, you need to ensure that the references you're storing in your struct have lifetimes that are tied to valid data that will outlive the struct itself. This may involve restructuring your code or using techniques like lifetimes, ownership, or borrowing to ensure that references remain valid for the required duration.