diff --git a/src/lifetime-elision.md b/src/lifetime-elision.md index eb1097dc8..eb43bd66c 100644 --- a/src/lifetime-elision.md +++ b/src/lifetime-elision.md @@ -5,10 +5,14 @@ compiler can infer a sensible default choice. ## Lifetime elision in functions -In order to make common patterns more ergonomic, Rust allows lifetimes to be +In order to make common patterns more ergonomic, lifetime arguments can be *elided* in [function item], [function pointer] and [closure trait] signatures. The following rules are used to infer lifetime parameters for elided lifetimes. -It is an error to elide lifetime parameters that cannot be inferred. +It is an error to elide lifetime parameters that cannot be inferred. The +placeholder lifetime, `'_`, can also be used to have a lifetime inferred in the +same way. For lifetimes in paths, using `'_` is preferred. Trait object +lifetimes follow different rules discussed +[below](#default-trait-object-lifetimes). * Each elided lifetime in the parameters becomes a distinct lifetime parameter. * If there is exactly one lifetime used in the parameters (elided or not), that @@ -23,6 +27,7 @@ Examples: ```rust,ignore fn print(s: &str); // elided +fn print(s: &'_ str); // also elided fn print<'a>(s: &'a str); // expanded fn debug(lvl: usize, s: &str); // elided @@ -41,22 +46,27 @@ fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded fn args(&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 - preferred fn new(buf: &mut [u8]) -> BufWriter; // elided fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded type FunPtr = fn(&str) -> &str; // elided type FunPtr = for<'a> fn(&'a str) -> &'a str; // expanded -type FunTrait = Fn(&str) -> &str; // elided -type FunTrait = for<'a> Fn(&'a str) -> &'a str; // expanded +type FunTrait = dyn Fn(&str) -> &str; // elided +type FunTrait = dyn for<'a> Fn(&'a str) -> &'a str; // expanded ``` ## Default trait object lifetimes The assumed lifetime of references held by a [trait object] is called its _default object lifetime bound_. These were defined in [RFC 599] and amended in -[RFC 1156]. Default object lifetime bounds are used instead of the lifetime -parameter elision rules defined above. +[RFC 1156]. + +These default object lifetime bounds are used instead of the lifetime parameter +elision rules defined above when the lifetime bound is omitted entirely. If +`'_` is used as the lifetime bound then the bound follows the usual elision +rules. If the trait object is used as a type argument of a generic type then the containing type is first used to try to infer a bound. @@ -78,45 +88,45 @@ If neither of those rules apply, then the bounds on the trait are used: trait Foo { } // These two are the same as Box has no lifetime bound on T -Box -Box +Box +Box // ...and so are these: -impl Foo {} -impl Foo + 'static {} +impl dyn Foo {} +impl dyn Foo + 'static {} // ...so are these, because &'a T requires T: 'a -&'a Foo -&'a (Foo + 'a) +&'a dyn Foo +&'a (dyn Foo + 'a) // std::cell::Ref<'a, T> also requires T: 'a, so these are the same -std::cell::Ref<'a, Foo> -std::cell::Ref<'a, Foo + 'a> +std::cell::Ref<'a, dyn Foo> +std::cell::Ref<'a, dyn Foo + 'a> // This is an error: struct TwoBounds<'a, 'b, T: ?Sized + 'a + 'b> -TwoBounds<'a, 'b, Foo> // Error: the lifetime bound for this object type cannot - // be deduced from context +TwoBounds<'a, 'b, dyn Foo> // Error: the lifetime bound for this object type + // cannot be deduced from context ``` -Note that the innermost object sets the bound, so `&'a Box` is still `&'a -Box`. +Note that the innermost object sets the bound, so `&'a Box` is still +`&'a Box`. ```rust,ignore // For the following trait... trait Bar<'a>: 'a { } // ...these two are the same: -Box> -Box + 'a> +Box> +Box + 'a> // ...and so are these: -impl<'a> Foo<'a> {} -impl<'a> Foo<'a> + 'a {} +impl<'a> dyn Foo<'a> {} +impl<'a> dyn Foo<'a> + 'a {} // This is still an error: struct TwoBounds<'a, 'b, T: ?Sized + 'a + 'b> -TwoBounds<'a, 'b, Foo<'c>> +TwoBounds<'a, 'b, dyn Foo<'c>> ``` ## `'static` lifetime elision @@ -136,7 +146,7 @@ struct BitsNStrings<'a> { } // BITS_N_STRINGS: BitsNStrings<'static> -const BITS_N_STRINGS: BitsNStrings = BitsNStrings { +const BITS_N_STRINGS: BitsNStrings<'_> = BitsNStrings { mybits: [1, 2], mystring: STRING, }; @@ -152,11 +162,11 @@ usual rules, then it will error. By way of example: const RESOLVED_SINGLE: fn(&str) -> &str = .. // Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`. -const RESOLVED_MULTIPLE: &Fn(&Foo, &Bar, &Baz) -> usize = .. +const RESOLVED_MULTIPLE: &dyn Fn(&Foo, &Bar, &Baz) -> usize = .. // There is insufficient information to bound the return reference lifetime // relative to the argument lifetimes, so this is an error. -const RESOLVED_STATIC: &Fn(&Foo, &Bar) -> &Baz = .. +const RESOLVED_STATIC: &dyn Fn(&Foo, &Bar) -> &Baz = .. ``` [closure trait]: types.html#closure-types diff --git a/src/trait-bounds.md b/src/trait-bounds.md index e4278db91..a1ffd454d 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -19,6 +19,7 @@ > _Lifetime_ : >       [LIFETIME_OR_LABEL] >    | `'static` +>    | `'_` [Trait] and lifetime bounds provide a way for [generic items][generic] to restrict which types and lifetimes are used as their parameters. Bounds can be