Why does this compile? (lifetimes)


#1

I’m not sure why the following code compiles. As per Bar’s declaration, all members should have the same lifetime, except as defined in main(), they don’t. Why does it work?

struct Foo<'a> {
    x: &'a i32,
}

struct Bar<'a> {
    f1: &'a Foo<'a>,
    f2: &'a Foo<'a>,
}

fn main() {
  let foo = Foo { x: &10 };
  {
    let foo2 = Foo { x: &20 };

    let bar = Bar {
        f1: &foo,
        f2: &foo2,
    };
  }

#2

Both of your Foos are Foo<'static> because you took a borrow of a literal.

So let’s change that:

fn main() {
  let x = 10;
  let foo = Foo { x: &x };
  {
    let x = 10;
    let foo2 = Foo { x: &x };

    let bar = Bar {
        f1: &foo,
        f2: &foo2,
    };
  }
}

You will see however that this still compiles. This is because, moreover, all of the places where 'a appears in your code are covariant, which means that a value with a longer lifetime argument is allowed to be used as a value with a shorter lifetime.


#3

Ok, I understand the covariance factor which explains why even if foo and foo2 have different lifetimes, it still compiles.

Referring to my first example, though foo and foo2 have a static lifetime, that does not mean that they should be accessible in any scope, correct? (scope is different than lifetime)


#4

Correct - Foo<'static> simply means it can live for the 'static lifetime (i.e. its internal reference(s) stays valid), but it doesn’t have to. This is no different than an owned value, like String - a String can also be kept alive for 'static lifetime because, trivially, it has no references. But, String values can come and go in more transient situations (far more common), and if one goes away, you can’t access it anymore.


#5

Thank you all for you great answers.