That's not correct. Person<'a>
is covariant in 'a
and so is &'a Person<'a>
. You can shorten both lifetimes when you make the call.
The problem in that example is that you can't have a borrow of something that lasts after said thing goes out of scope.
let val: &str;
let name = String::from("john");
{
let person = Person { // Person<'p>
name: &name, // `name` is borrowed for `p`
};
// Create `&'v Person<'v>` for method call, get back `&'v str`
// `'p: 'v` and `person` is borrowed for `'v`
val = person.get_name();
} // `person` goes out of scope -- incompatible with `'v` being alive
// Use of `'v` -- requires `'v` being alive
println!("{}", val);
// End of block drops `name`, incompatible with `'p` being alive
In contrast here
let val: &str;
let name = String::from("john");
{
let person = Person { // Person<'p>
name: &name, // `name` is borrowed for `p`
};
// for simplicity let's say `val: &'p str` and this is a copy
val = person.name;
} // `person` goes out of scope
// Under this interpretation this is just a use of `'p`
println!("{}", val);
// End of block drops `name`, incompatible with `'p` being alive
A simple way to think of this is that you just copied the reference out of person
. It's okay if 'p
is longer than the inner block even though Person
goes out of scope, just like it's okay to have a &'static
in a local variable.
The actual borrow analysis is more complicated, but hopefully you understand how the compiler can prove everything is ok for this example.
I believe this is how it actually works, but probably it's not worth thinking so hard about for the example since "you just copied the reference out" also justifies the compilation succeeding.
EDIT: Ehh, sorry, what I had here wasn't correct and I don't feel like fixing it (as it basically does end up effectively being "you made a copy" I believe now) so I'm just going to deleted it.
Here's the signature now:
// fn get_name(&self) -> &'a str
fn get_name<'s>(self: &'s Person<'a>) -> &'a str
where
'a: 's // implicit bound from the `&'s ... 'a` nesting
So now when you call this method, you can borrow self
for just the call expression ('s
) and return some longer lifetime ('a
). Compared to the first example above,
// vv DIFFERENT new lifetime (and `'v: 's`)
// Create `&'s Person<'v>` for method call, get back `&'v str`
// `'p: 'v` and `person` is borrowed for `'s` << DIFFERENT
val = person.get_name();
's
isn't used anywhere else so it can expire immediately, which means person
isn't borrowed when it goes out of scope. The reborrow of the field is hidden away in the method (beyond an API contract that the compiler assumes just works), so the more complicated "shallow access" logic hidden under the fold above doesn't even need apply. It's sort of like you codified the "take a copy" interpretation into the method signature, if you will.
If you actually need a borrowing struct that you hand out borrows from, this is almost always what you want/mean: You can borrow me very briefly (&'s self)
and I can give you part of the borrow I'm holding on to (something with 'a
). It's how iterators that hand out references work, for example.
I didn't see much else to comment on, but let me know if you have any follow-up questions.