The only time I've ever used multiple explicit lifetimes, I was accidentally trying to trick the compiler into accepting shared mutability. The compiler was not fooled.
This is why elision is so awesome, it takes care of almost all the cases where you need a "regular" lifetime specification on a function. When elision doesn't works usually there is something you need to specify.
The subtyping works for callers; lifetimes get stretched and sqeezed to fit the function signature. But the function body itself won't compile when you're doing things like stuffing references into other references unless the lifetimes are right.
let foo = {
let age = 0;
Foo { age: &age }
};
The `age` variable goes out of scope at the } (i.e. the maximum possible lifetime for &age ends there), and hence letting the `Foo` escape from that scope would be a bad idea.(NB. this applies to the "core" lifetime'd types like `&'c T` too: that is really just a nicer way to write a parameterised type like `Ref<'c, T>`. So the rule "cannot return a reference to a local variable" is the same rule that stops a `Foo<'c>` living too long.)
When you say `Foo<'c>`, all you're saying is that each `Foo` instance has an associated lifetime `'c`, similar to a type parameter. When you add the `x: &'c u8` field, then you're saying that "this lifetime is the lifetime of the inner u8".
> Am I correct in thinking that, in reality, 'c must live as long or outlive the struct
For the specific example, yes. It's possible to have an example where 'c must be shorter lived, and cannot outlive the struct.
If you had an &mut instead of & there, then 'c must live exactly as long as the struct.
> It's possible to have an example where 'c must be shorter lived, and cannot outlive the struct.
I'm interested in such an example. Could you provide one?
The idea was to have something like
struct Foo<'a> {f: fn(&'a u8)}
should only be able to accept pointers that live shorter than the struct. But contravariance seems to have been removed.
Think of it like generics. What's the difference between:
and "How's T different from U"? That's not the right question to ask -- over here Bar lets T be different from U, whereas in Foo both x and y must have the same type.With the example above
this means that there are two references of independent lifetimes. It could also be: which means that the lifetimes must match, or even which means that 'b is a subset of 'a. (This becomes useful if a struct stores a borrow to a thing and then a borrow of something extracted from that thing)While the first case is the most common (and theoretically could be elided), it's still often a tossup and it's clearer when you know that a struct is borrowing things.