Search code examples
rustscopelifetime

In Rust, is there a difference in drop order for a Box:ed struct compared to a plain struct?


The following code does not compile:

struct Ref<'a> {
    nbr: &'a u32,
}

fn func<'a>() {
    let nbr: u32 = 42;
    let _a_ref: Box<Ref<'a>> = Box::new(Ref { nbr: &nbr });
}

fn main() {
    func();
}

The compiler complains that 'nbr' does not live long enough and that it is dropped at the end of func() while still borrowed. I have searched basically everywhere but I cannot understand why this error occurs. The variables are supposed to be dropped in reverse order compared to declaration, so the boxed Ref containing the reference should be dropped before nbr is dropped, right?

If I change func() into:

fn func<'a>() {
    let nbr: u32 = 42;
    let _a_ref = Ref { nbr: &nbr };
}

it builds just fine! So there is some difference to the required lifetime / scope for a boxed reference - but I cannot find any clear and simple explanation to this apparently basic question.

To make it even more confusing, I noted that if I state the type of _a_ref like this:

fn func<'a>() {
    let nbr: u32 = 42;
    let _a_ref: Ref<'a> = Ref { nbr: &nbr };
}

I once again get the 'nbr' does not live long enough error.

Lastly, I played with the underscore, like this:

fn func<'a>() {
    let nbr: u32 = 42;
    let _a_ref: Ref<'_> = Ref { nbr: &nbr };
}

And now it builds just fine again! What is the difference between these 3 ways of using the non-boxed Ref struct? And how do they all compare to the boxed variant?


Solution

  • The Box is not the problem here, 'a is.

    &nbr has the lifetime of nbr. But 'a is a caller-chosen lifetime, which might (and even always will) be larger than the lifetime of nbr. So you cannot assign Ref<'nbr> to Ref<'a>.

    Ref<'_> means "let the compiler infer the lifetime", and is basically equivalent to not specifying the type at all.