E.g. it will have the effect that you cannot do the call to foo
twice in your example
#![feature(type_alias_impl_trait)]
use std::future::Future;
type FooRet<'c> = impl 'c + Future<Output = ()>;
fn foo<'a, 'b>(it: &'a mut &'b ()) -> FooRet<'b>
where
'a: 'b,
{
async move {
drop(it);
}
}
#[tokio::main]
async fn main() {
let v: () = ();
let mut r: &() = &v;
foo(&mut r).await;
foo(&mut r).await; // error
}
The quick explanation:
- First: what does
T: 'a
mean?- it mean that the type
T
cannot use/mention/contain any lifetimes that are shorter than'a
. - on way to phrase it:
T
must be such that every reference that a value of typeT
contains has a lifetime longer than'a
. - another more syntactic interpretation: If you write the concrete type that the parameter
T
gets instantiated with, that type must not, syntactically, mention any lifetime shorter than'a
.- e.g. for
T == &'b ()
, the boundT: 'a
is only true if'b
is no shorter than'a
, i.e.'b
outlives'a
, i.e.'b: 'a
.
- e.g. for
- The bound
T: 'a
is a necessary condition for the type&'a T
or&'a mut T
to be well-formed.- Think of them as
struct Ref<'a, T> where T: 'a { ... }
(note thewhere
bound!), just thatRef<'a, T>
has special syntax&'a T
. - This is also why
&'a mut &'b ()
discussed earlier comes with a bound: The bound&'b (): 'a
, which in turn requires'b: 'a
. HereT
is&'b ()
.
- Think of them as
- it mean that the type
- The
impl Trait + 'a
really only means that the return typeT
must fulfillT: Trait + 'a
, which means it fulfills bothT: Trait
andT: 'a
. The side-effect that this signature also mentions the lifetime'a
is important, too. As mentioned, itās the most important thing about this+ 'a
in usual usage withouttype_alias_impl_trait
. - Struct/enums you define follow the syntactic rule for
T: 'a
bounds as-well:- A
struct Foo<'a, 'b> = { /* some fields */ }
always behaves such thatFoo<'a, 'b>: 'c
is fulfilled if and only if'a: 'c
and'b: 'c
are fulfilled.
- A
- A type defined by
type_alias_impl_trait
, i.e.type Foo<'a, 'b> = impl Trait;
behaves exactly like structs / enums in this case.- This means that even a type
Foo<'a, 'b> = impl 'a + Trait;
would only fulfillFoo<'a, 'b>: 'a
if'b: 'a
. This is weird because one would expect thatFoo<'a, 'b>
implements'a + Trait
, but it really ā effectively ā doesnāt. (Example code.) Thatās the weirdness I was referring to, and itās what makes writing the'a + ā¦
fairly useless intype_alias_impl_trait
aliases.
- This means that even a type
If you havenāt already, you might also be interested in reading this blog post
rust-blog/common-rust-lifetime-misconceptions.md at master Ā· pretzelhammer/rust-blog Ā· GitHub