I've constructed the most basic example I can for lifetimes to understand them. Consider a function that, according to some condition, returns a reference to an element at an index:
fn get_min<T: PartialOrd + Ord>(left: &Vec<T>, right: &Vec<T>, index: usize) -> &T {
if &left[index] < &right[index] {
&left[index]
} else {
&right[index]
}
}
Suppose you add the following lifetimes:
fn get_min<'a, 'b: 'a, 'c: 'a, T: PartialOrd + Ord>(left: &'b Vec<T>, right: &'c Vec<T>, index: usize) -> &'a T {
if &left[index] < &right[index] {
&left[index]
} else {
&right[index]
}
}
If the returned reference goes out of scope, will it be dropped, even if the vectors continue not to be dropped? In my case, the vectors stay around for the duration of the program, and I don't want the returned reference to.
The compiler will choose a lifetime
'athat is as small as possible. In some situations where the same lifetime is linked to multiple things, it may be longer than you expect, but regardless the compiler does so to reduce conflicts and therefore accept as many valid programs as possible. That principle is definitely in play here since immutable references are covariant with respect to their lifetimes (meaning they can be minimized).Another important part of your question is about dropping references. References do not implement
Drop; they have no drop logic and are alsoCopy(which would conflict withDrop). Though since types holding a lifetime can "lock out" mutations or other action on the referent, it is important to know when this "lock" stops being held. Since non-lexical lifetimes were introduced, this is no longer related to the scope of the reference, but rather ends when the reference is last used. So explicitly dropping references (by introducing a scope) is not ever needed.Lets consider an example using your function but from a caller's perspective:
The scope of
minstarts from its declaration until the end ofmain. However, if that were the lifetime that it borrowed fromvec_aorvec_b, then the.clear()calls would conflict and trigger a compiler error. Instead the compiler allows this since you aren't accessingminafter theprintln!statement and thus that is where the lifetime of'aends.So to answer your question:
The returned reference need not be the lifetime of the vectors, and will most likely be much shorter. If references held on forever that would severely limit what you could do.
Even if
vec_aandvec_bwere created statically and thus have a'staticlifetime, references derived from them will borrow from them as small a lifetime as the compiler can make them.As a side note, the additional lifetimes
'band'care not necessary here. Sinceleftandrightare immutable references, and thus are covariant with respect to their lifetime, their lifetimes will already be as small as possible as deduced at the callsite (just enough to support'a). In this case a single lifetime is sufficient and expresses the same constraints: