Understand function lifetime parameters
First, note that elided lifetimes in function signatures are invisible lifetime parameters on the function.
#![allow(unused)]
fn main() {
fn zed(s: &str) {}
}
#![allow(unused)]
fn main() {
// same thing
fn zed<'s>(s: &'s str) {}
}
When you have a lifetime parameter like this, the caller chooses the lifetime. But the body of your function is opaque to the caller: they can only choose lifetimes just longer than your function body.
So when you have a lifetime parameter on your function (without any further bounds), the only things you know are
- It’s longer than your function body
- You don’t get to pick it, and it could be arbitrarily long (even
'static) - But it could be just barely longer than your function body too; you have to support both cases
And the main corollaries are
- You can’t borrow locals for a caller-chosen lifetime
- You can’t extend a caller-chosen lifetime to some other named lifetime in scope
- Unless there’s some other outlives bound that makes it possible
Here’s a couple of error examples related to function lifetime parameters:
#![allow(unused)]
fn main() {
fn long_borrowing_local<'a>(name: &'a str) {
let local = String::new();
let borrow: &'a str = &local;
}
fn borrowing_zed(name: &str) -> &str {
match name.len() {
0 => "Hello, stranger!",
_ => &format!("Hello, {name}!"),
}
}
}