There have been a lot of lifetime threads lately, and I can't recall who I pointed where, so forgive me if I'm repeating myself to you.
This portion of the Nomicon is addressing a common expectation people learning Rust have, which is that after calling a method that looks like so...
fn exclusive_borrow_shared_return(&mut self) -> &Thing { /* ... */ }
...self
will no longer be mutably borrowed, because the returned value is a shared borrow.
However, that's not how the lifetimes work. In desugared form, the signature is:
fn exclusive_borrow_shared_return<'a>(&'a mut self) -> &'a Thing
And the most simple way I can describe it is that "self
must be exclusively borrowed for the same duration as the returned &'a Thing
is valid."
For the behavior to match the intuition, it would have to be some sort of two-phased borrow -- two distinct borrows in succession. A brief exclusive borrow of self
for the duration of the method call, immediately and seamlessly followed by a shared borrow of both self
and the returned value.
As noted in this article, we can't change the existing rules to work like that, as the existing rules are relied upon for soundness. It would have to be some new feature of the language, which we don't have so far.
Let's do a thought experiment within the current Rust rules, anyway. The experiment is: can we mutably borrow for a short period and return a shared value that is valid for a longer period? Here's what such a method might look like, from a lifetime declaration standpoint:
fn short_to_long<'long: 'short, 'short>(&'short self) -> &'long i32 {
todo!()
}
It compiles as-is. But if we actually try to return a reference to a field here, we cannot:
error: lifetime may not live long enough
--> src/lib.rs:7:9
|
6 | fn short_to_long<'long: 'short, 'short>(&'short self) -> &'long i32 {
| ----- ------ lifetime `'short` defined here
| |
| lifetime `'long` defined here
7 | &self.field
| ^^^^^^^^^^^ associated function was supposed to return data with lifetime `'long` but it is returning data with lifetime `'short`
|
= help: consider adding the following bound: `'short: 'long`
If we followed the advice, we would have both
'long: 'short, // 'long is valid for at least 'short
'short: 'long // 'short is valid for at least 'long
And that means the lifetimes would have to be equal, and we're back to the signature where the returned lifetime and the input lifetime are the same.
You can reborrow a reference for some shorter duration, but you can not reborrow a reference for some longer duration. In order to create the borrow of the field for 'x
, you yourself had to have access for at least 'x
.
When exactly you can "shrink" lifetimes or not, or even grow them in some cases, is determined by a property called variance. But a good starting point is, "you can't reborrow something for longer than you borrowed it." If I rent a house for a week, I can't let someone else use the bedroom for a month.
You can't borrow self
for 'short
and then hand out a borrow of some field for 'long
, either.