In order to make common patterns more ergonomic, Rust allows lifetimes to be elided in function signatures.
A lifetime position is anywhere you can write a lifetime in a type:
&'a T &'a mut T T<'a>
Lifetime positions can appear as either "input" or "output":
fntypes, and the traits
FnOnce, input refers to the types of the formal arguments, while output refers to result types. So
fn foo(s: &str) -> (&str, &str)has elided one lifetime in input position and two lifetimes in output position. Note that the input positions of a
fnmethod definition do not include the lifetimes that occur in the method's
implheader (nor lifetimes that occur in the trait header, for a default method).
implheaders, all types are input. So
impl Trait<&T> for Struct<&T>has elided two lifetimes in input position, while
impl Struct<&T>has elided one.
Elision rules are as follows:
Each elided lifetime in input position becomes a distinct lifetime parameter.
If there is exactly one input lifetime position (elided or not), that lifetime is assigned to all elided output lifetimes.
If there are multiple input lifetime positions, but one of them is
&mut self, the lifetime of
selfis assigned to all elided output lifetimes.
Otherwise, it is an error to elide an output lifetime.
fn print(s: &str); // elided fn print<'a>(s: &'a str); // expanded fn debug(lvl: usize, s: &str); // elided fn debug<'a>(lvl: usize, s: &'a str); // expanded fn substr(s: &str, until: usize) -> &str; // elided fn substr<'a>(s: &'a str, until: usize) -> &'a str; // expanded fn get_str() -> &str; // ILLEGAL fn frob(s: &str, t: &str) -> &str; // ILLEGAL fn get_mut(&mut self) -> &mut T; // elided fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command // elided fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded fn new(buf: &mut [u8]) -> BufWriter; // elided fn new(buf: &mut [u8]) -> BufWriter<'_>; // elided (with `rust_2018_idioms`) fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded