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:
fn main() { &'a T &'a mut T T<'a> }&'a T &'a mut T T<'a>
Lifetime positions can appear as either "input" or "output":
For fn
definitions, input refers to the types of the formal arguments
in the fn
definition, 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 fn
method definition do not
include the lifetimes that occur in the method's impl
header
(nor lifetimes that occur in the trait header, for a default method).
In the future, it should be possible to elide impl
headers in the same manner.
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 &self
or
&mut self
, the lifetime of self
is assigned to all elided output lifetimes.
Otherwise, it is an error to elide an output lifetime.
Examples:
fn main() { fn print(s: &str); // elided fn print<'a>(s: &'a str); // expanded fn debug(lvl: uint, s: &str); // elided fn debug<'a>(lvl: uint, s: &'a str); // expanded fn substr(s: &str, until: uint) -> &str; // elided fn substr<'a>(s: &'a str, until: uint) -> &'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<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded }fn print(s: &str); // elided fn print<'a>(s: &'a str); // expanded fn debug(lvl: uint, s: &str); // elided fn debug<'a>(lvl: uint, s: &'a str); // expanded fn substr(s: &str, until: uint) -> &str; // elided fn substr<'a>(s: &'a str, until: uint) -> &'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<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded