When searching for documentation about conservative impl trait, I found this example:
struct A {
x: [(u32, u32); 10]
}
impl A {
fn iter_values<'a>(&'a self) -> impl 'a + Iterator<Item = u32> {
self.x.iter().map(|a| a.0)
}
}
What does the lifetime 'a
mean in the return type?
I am aware of this question about lifetime bound in Box
, but I think that the usecases are different. If I understand well the answer:
trait object is only valid for the lifetime 'a
It means that the trait object that lives somewhere in the heap will last during a lifetime 'a
.
But here, this is not a trait object but a concrete object that lives in the stack. So the compiler does not need to have hints about its lifetime.
What am I missing about this?
The syntax impl Iterator<Item = u32> + 'a
means
impl ...
part.u32
values. That's the Iterator<Item = u32>
part.'a
. That's the + 'a
part.In your example, the returned iterator contains references to self
, so it must not be allowed to live longer than the instance of A
, otherwise it would be invalid. The concrete type (if we could write it) would be iter::Map<slice::Iter<'a, (u32, u32)>, <closure>>
— note that it has a 'a
in it.
It means that the trait object that lives somewhere in the heap will last during a lifetime
'a
.
This is not quite true. Both cases have the same meaning: the unspecified concrete type may contain a reference. With a trait object, the concrete type is behind a pointer of some kind (Box
, &
, Rc
, etc.). With impl trait, the concrete type is placed directly on the stack.
this is not a trait object but a concrete object that lives in the stack
Trait objects do not require the heap; they can utilize only the stack:
let x: &std::fmt::Display = &42;
println!("{}", x);
See also:
It means that the trait object that lives somewhere in the heap will last during a lifetime
'a
.
Not quite.
'a
here does not exactly specify, it only places an upper-bound on the lifetime of the object. Whether the object is located on the heap or on the stack does not matter: the compiler must ensure that the lifetime of this object does not exceed 'a
.
The lifetime represents a relationship between referred and referent, and is used to ensure that the referent will never outlive the referred. As such, it places an upper-bound on the lifetime of the referent and a lower-bound on the lifetime of the referred.
The compiler could derive the necessary lifetime from the actual concrete type that is returned by the function, however it would require that the type-checker be able to look at the function implementation to perform its job.
Documenting the lifetime constraint at the interface boundary is thus more friendly to both humans and compiler: it allows local reasoning.
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