From the Rust documentation:
Rust supports powerful local type inference in the bodies of functions, but it deliberately does not perform any reasoning about types for item signatures. However, for ergonomic reasons, a very restricted secondary inference algorithm called “lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely with inferring lifetime parameters using three easily memorizable and unambiguous rules. This means lifetime elision acts as a shorthand for writing an item signature, while not hiding away the actual types involved as full local inference would if applied to it.
I don't understand what this means. What are item signatures? What does "infer lifetime parameters" mean? Some examples or analogies would be helpful.
An item signature is the bit which gives the name and types of your function, i.e. everything you need to call it (without needing to know how it's implemented); for example:
fn foo(x: u32) -> u32;
Here's another which takes a &str
reference:
fn bar<'a>(s: &'a str) -> &'a str;
In Rust, all references have an attached lifetime; this is part of the type. The above bar
function says more than just "this function takes a reference to a string and returns another one". It says "this function takes a string reference, and returns another which is valid for as long as the one it's given. This is an important part of Rust's ownership system.
However, it's annoying and a pain to specify these lifetimes every time, so Rust has "lifetime elision" (i.e. "not explicitly writing them out"). All that means is that for a few very common cases, you can leave the lifetime annotations out and Rust will implicitly add them for you. This is purely a convenience for programmers so that they don't have to write so many lifetimes in "obvious" cases.
The rules are listed in the book, but for completeness they are:
fn f(x: &T, y: &U)
means:
fn f<'a, 'b>(x: &'a T, y: &'b U)
i.e. there's no automatic link between those lifetimes.
struct U<'a> {} // struct with a lifetime parameter
fn f(x: &T) -> &U
becomes:
fn f<'a>(x: &'a T) -> &'a U<'a>
&self
or &mut self
(i.e. it's a method), then all the elided output lifetimes get the same as self
. This covers the common case that a method returns a reference to one of its fields. For example:impl S {
fn get_my_item(&self, key: &str) -> &str {}
}
becomes:
fn get_my_item<'a,'b>(&'a self, key: &'b str) -> &'a str // use the self lifetime
The documentation has some more examples.
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