trait Foo<T> {
fn bar(&self, t: &mut T);
}
fn baz<'a, T>(foo: impl Foo<T> + 'a) {}
Does the baz
function here imply a lifetime constraint of T: 'a
?
If so, how can I change Foo or baz to avoid (or relax) this constraint as it isn't a type that's stored or dropped when Foo is dropped?
It doesn’t. To demonstrate:
trait Foo<T> {
fn bar(&self, t: &mut T);
}
fn baz<'a, T>(foo: impl Foo<T> + 'a) {}
impl<T> Foo<T> for () {
fn bar(&self, t: &mut T) {}
}
// test without `T: 'static` bound
fn test<T>() {
baz::<'static, T>(());
}
Do note that in practice some your types implementing Foo
might come with a comparable restriction though. E.g. if you implement impl<T> Foo<T> for SomeStruct<T>
, then SomeStruct<T>
can only be used for impl Foo<T> + 'a
if the bound SomeStruct<T>: 'a
and hence T: 'a
is implemented.
A similar thing could apply to trait objects. E.g. if you have a generic impl
lifting Foo<T>
implementations from S: ?Sized
to Box<S>
, and then try to pass Box<dyn Foo<T>>
for the impl Foo<T> + 'a
, then a Box<dyn Foo<T>>: 'a
requirement would also imply a T: 'a
requirement.
1 Like
No. The + 'a
is a (explicit) bound on the implementing type, not on T
.
1 Like
E.g. if you implement impl<T> Foo<T> for SomeStruct<T>
, then SomeStruct<T>
can only be used for impl Foo<T> + 'a
if the bound SomeStruct<T>: 'a
and hence T: 'a
is implemented
Can you explain this case a bit more? This applies even while SomeStruct does not store a T?
Can I do something to prevent the constraint from applying to T if the struct doesn't store one?
Your function can be rewritten like so:
fn baz<'a, T, F: Foo<T> + 'a>(foo: F) {}
And the bounds in question are:
F: Foo<T>,
F: 'a
Which, given F = SomeStruct<T>
, are:
SomeStruct<T>: Foo<T>,
SomeStruct<T>: 'a
Outlives bounds like SomeStruct<T>: 'a
are defined syntactically, and in this case, requires T: 'a
.
No, it's required syntactically and there's not an override.
The lifetime is meaningless in your example so this may be an XY problem.
Why must the lifetime constraint apply to T
if SomeStruct only contains a fn(T)
?
If no T will be dropped, it seems like the constraint is applied for no reason?
I am using closures and function pointers quite a bit so I am trying to understand the relationship between the lifetime constraints and generics in that case.
It use to work more like that (10 years ago), but was unsound and buggy. This is the relevant RFC.
https://rust-lang.github.io/rfcs/1214-projections-lifetimes-and-wf.html
For a concrete example, if fn(Cell<&'a str>)
was 'static
, you could cast it to dyn Any
and then downcast it to... what? It can't soundly be fn(Cell<&'b str>)
for a different lifetime 'b
, but there isn't a finite set of lifetimes.
1 Like