The third rule of lifetime elision says
If there are multiple input lifetime parameters, but one of them is
&self
or&mut self
because this is a method, then the lifetime ofself
is assigned to all output lifetime parameters. This makes writing methods much nicer.
Here is the tutorial describing what happened for this function
fn announce_and_return_part(&self, announcement: &str) -> &str
There are two input lifetimes, so Rust applies the first lifetime elision rule and gives both
&self
andannouncement
their own lifetimes. Then, because one of the parameters is&self
, the return type gets the lifetime of&self
, and all lifetimes have been accounted for.
We can show that all the lifetimes are not accounted for since it is possible that announcement
will have a different lifetime than &self
:
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
announcement
}
}
fn main() {
let i = ImportantExcerpt { part: "IAOJSDI" };
let test_string_lifetime;
{
let a = String::from("xyz");
test_string_lifetime = i.announce_and_return_part(a.as_str());
}
println!("{:?}", test_string_lifetime);
}
The lifetime of announcement
is not as long as &self
, so it is not correct to associate the output lifetime to &self
, shouldn't the output lifetime be associated to the longer of the input?
Why is the third rule of lifetime elision a valid way to assign output lifetime?
Lifetimes are what the Rust compiler uses to keep track of how long references are valid for. Checking references is one of the borrow checker's main responsibilities. Lifetimes help the borrow checker ensure that you never have invalid references.
Rust uses lifetime parameters to avoid such potential run-time errors. Since the compiler doesn't know in advance whether the if or the else block will execute, the code above won't compile and an error message will be printed that says, “a lifetime parameter is expected in compare 's signature.”
'_ , the anonymous lifetime Rust 2018 allows you to explicitly mark where a lifetime is elided, for types where this elision might otherwise be unclear. To do this, you can use the special lifetime '_ much like you can explicitly mark that a type is inferred with the syntax let x: _ = ..; .
No, the elision rules do not capture every possible case for lifetimes. If they did, then there wouldn't be any elision rules, they would be the only rules and we wouldn't need any syntax to specify explicit lifetimes.
Quoting from the documentation you linked to, emphasis mine:
The patterns programmed into Rust's analysis of references are called the lifetime elision rules. These aren't rules for programmers to follow; the rules are a set of particular cases that the compiler will consider, and if your code fits these cases, you don't need to write the lifetimes explicitly.
The elision rules don't provide full inference: if Rust deterministically applies the rules but there's still ambiguity as to what lifetimes the references have, it won't guess what the lifetime of the remaining references should be. In this case, the compiler will give you an error that can be resolved by adding the lifetime annotations that correspond to your intentions for how the references relate to each other.
The lifetime of
announcement
is not as long as&self
, so it is not correct to associate the output lifetime to&self
Why is the third rule of lifetime elision a valid way to assign output lifetime?
"correct" is probably not the right word to use here. What the elision rules have done is a valid way, it just doesn't happen to be what you might have wanted.
shouldn't the output lifetime be associated to the longer of the input?
Yes, that would be acceptable for this example, it's just not the most common case, so it's not what the elision rules were aimed to do.
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With