error: lifetime may not live long enough
--> src/lib.rs:9:5
|
8 | fn get_ref_from_mut_ref<'s, 'a>(s: &'s S<'a>) -> &'a u32 {
| -- -- lifetime `'a` defined here
| |
| lifetime `'s` defined here
9 | s.a_mut
| ^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'s`
This surprised me and I don't understand a few things here:
In both cases, I'm clearly returning a reference with lifetime 'a, but in the mutable case it gets converted to 's for some reason. Why does this happen in the mutable case and not in the immutable case?
Is there a name for this behavior, something I read more about in the book/reference/nomicon etc?
Is the function get_ref_from_mut_ref() actually incorrect? In other words, if the function compiled, is there an example where it would it would violate Rust constrains?
Immutable, shared references implement Copy. If you have an &'a u32, you can get another &'a u32 just like copying any other type.
Mutable, exclusive references do not implement Copy. They cannot, because if they did, they would no longer be exclusive. Or from a slightly different angle, the 'a in &'a mut u32 means roughly “you may mutate the u32 for as long as ’a”, which is certainly incompatible with an &'a u32 existing.
Mutable references do, however, support reborrowing, which is where the mutable reference becomes itself borrowed and you get a new mutable or immutable reference to its referent or one of its referent’s parts. That's what happened in get_ref_from_mut_ref. Reborrowing from the mutable reference acts a lot like borrowing a struct field or such: the borrow is valid for as long as the reference to the struct or reference is, in this case 's.
Reborrowing is implicit, just like copying, and you're probably using it many times without noticing. In particular, every time you use a mutable reference twice in the same function, you are reborrowing it the first time, to create a dependent mutable reference that has a shorter lifetime which does not conflict with the lifetime of the second usage. Sometimes in generic code you can find you need to do this explicitly, writing &mut *some_ref.
The problem is “mutable references are exclusive”. The behavior you are encountering is “reborrowing”. Unfortunately, the official documentation on reborrowing is basically nonexistent.
If it compiled, you could use it to get an &'a u32 that coexisted with a usable &'a mut u32, thus violating immutability and exclusivity.
@kpreid Thanks for the detailed response, that completely clarifies it. I've heard about reborrowing but I didn't internalize it yet, so it's helpful to encounter it in my own example. I also really appreciate the wider context you have given in your answer.
I guess I missed the root cause[1] because reborrowing added a layer of implicit behavior, which made the error more cryptic from my beginner's perspective. Do I understand correctly that if reborrowing didn't exist, the error would have been something like "cannot borrow a_mut as immutable because it is also borrowed as mutable"?
If reborrowing did not exist at all, mutable references would be nearly impossible to make use of. Any time you write &self.foo or &mut self.foo in a method with &mut self in the signature, that's another sort of reborrow.
If reborrowing existed but was not implicit for mutable references, you might get a type error like “expected &u32, found &mut u32”, and you'd have to write &*s.a_mut to get the conversion.
Or maybe not. It’s hard to say exactly because reborrowing is so pervasive in how mutable references are actually used.