In this lesson, you will learn how Rust determines if a generic type can be safely swapped for another based on the lifetimes they contain.
The Problem of "Fitting In"
You already know that if you have a lifetime 'long that outlives 'short, then any reference valid for 'long can be used where a reference for 'short is required. This is lifetime subtyping.
But what happens when we put those references inside a generic wrapper, like &'a T? Variance is the set of rules that tells the compiler: "If T is a subtype of U, is Wrapper<T> a subtype of Wrapper<U>?"
Covariance
Most types in Rust are covariant. This means the "subtyping" relationship is preserved. For example, a reference &'a T is covariant over 'a. If 'long : 'short (meaning 'long is at least as long as 'short), then &'long T is a subtype of &'short T.
Think of this as "widening": you can safely treat a long-lived reference as a shorter-lived one because the data will definitely still be there.
Contravariance
Contravariance is the opposite: the relationship is flipped. This is rare in Rust, but it occurs in function types regarding their arguments.
If you have a function that expects a long-lived reference, it is actually more flexible than a function that expects a specific, short-lived reference. A function that can process anything that lives for 'short is "smaller" in scope than a function that requires a strict 'long lifetime.
Why Does This Matter?
Consider this snippet:
fn takes_short(s: &'short str) {}
let long_str: &'long str = "hello";
// This works because &T is covariant over its lifetime!
takes_short(long_str);
If the compiler didn't understand that &'long str fits into &'short str, you would have to manually cast your lifetimes every single time you passed a variable into a function. Variance handles this plumbing for you automatically, ensuring that your references are always "safe to shorten" but never "unsafe to lengthen."
Key Takeaway: Covariance allows a generic type to be used where a "smaller" or "shorter" version of its lifetime is expected, making Rust code flexible and intuitive.