So, generally, the lifetimes exist to enforce Rust's guarantees around borrows and memory safety. One core principle is "no two active &mut
to the same memory", which requires &mut
s to move and not be copied. But under this system, you couldn't have a method like this without reborrowing:
fn bar(s: &mut String, one: &str, two: &str) {
s.push_str(one); // if `s` gets moved
s.push_str(two); // you can't use it anymore and this wouldn't work
}
And of course, that's way too restrictive; hence, reborrowing.
In terms of the example, if there wasn't a reborrow when you assigned to sss
, you wouldn't be able to use mut_ref_s
anymore.
Furthermore, lifetimes can be considered part of the definition of a type. For example, this won't compile, because the lifetimes may not be compatible:
fn foo<'a, 'b>(r: &'a str) -> &'b str {
r
}
In this sense, &'long mut String
can be considered a subtype of &'short mut String
. The relationships become more complicated at the types become more complicated.
However, once a lifetime is determined (either by compiler inference or due to the labels you've used), it is not changed -- the type is static, just like other types in Rust. At that point, if you need to reborrow for some reason (like a method call or assignment), but still use the original variable, the reborrow will have to have a shorter lifetime than the original variable.
So let's look at your example again, but in a context where you can force the lifetimes by giving them names:
fn example<'a>(mut_ref_s: &'a mut String) {
// Unlike before, these have the same type _including lifetime_
let sss: &'a mut String;
// Even though this is a reborrow, it has a lifetime that is exactly as
// long as `mut_ref_s`
sss = mut_ref_s;
// That means we can't use `mut_ref_s` anymore -- only one `&mut` can be
// usable at a time, and the most recent reborrow "wins". So no more
// reborrows for `mut_ref_s`. (We could still use `sss` though.)
dummy(mut_ref_s);
// You can't move it while it's reborrowed in `sss` either.
let ss = mut_ref_s;
}
When we've forced sss
and mut_ref_s
to have the same type including lifetime, the code no longer compiles.
Thus, if mut_ref_s
wasn't coerced to a supertype (shorter lifetime) in your original example, it wouldn't have compiled.