Let's simplify the problem:
trait Foo {}
fn make_dyn_foo<F: Foo>(f: F) -> Box<dyn Foo> {
Box::new(f)
}
This code gives this error:
error[E0310]: the parameter type `F` may not live long enough
--> src/lib.rs:4:5
|
4 | Box::new(f)
| ^^^^^^^^^^^ ...so that the type `F` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
3 | fn make_dyn_foo<F: Foo + 'static>(f: F) -> Box<dyn Foo> {
| +++++++++
The error is fundamentally the same as yours. Adding a 'static
bound would fix the problem, but we don't want to restrict F
to 'static
types, so another solution is needed.
The problem is that dyn Foo
is implicitly a dyn Foo + 'static
. But what does that mean? Well, when you a trait object there's actually an instance of a concrete type that has been erased into that trait object. That type however may have a lifetime, meaning you can't let the instance life forever, you can only do that until the lifetime is valid. Thus trait objects actually carry a lifetime, like dyn Trait + 'a
, where the 'a
represents how much the instance behind the trait object can live.
Now, how does this connect to your problem? Well, you're putting an F
, which could have any lifetime, inside a dyn Foo + 'static
, which requires the type to have a 'static
lifetime (with this I mean that F: 'static
holds). Hence the suggestion in the error, which would fix your problem, but would also be overly restricting.
There's however an alternative: changing the return type to allow non-'static
types, and linking the lifetime of the input to the output. This can be done by introducing a lifetime (let's call it 's
), and changing the return type of Box<dyn Foo + 's>
. This lifetime doesn't necessarily have to be 'static
, so you can get rid of the 'static
bound. However you still have the requirement that whatever you put inside the dyn Foo + 's
must satisfy the lifetime 's
, so this needs s F: 's
bound.
You might ask why you need to annotate both the input and the output types with that lifetime. That's because you're linking them. You're taking the input and saying "let's call 's
its lifetime", and then you go on the output and say "this is only valid for the lifetime 's
, because it somehow contains and instance of the input". Note that this valid in general: a single lifetime parameter doesn't do anything, its power comes only from linking it to different parameters.
And here's the fixed code:
trait Foo {}
fn make_dyn_foo<'s, F: Foo + 's>(f: F) -> Box<dyn Foo + 's> {
Box::new(f)
}
Your case is pretty similar to this, except you have two trait objects, and you need to change both of them.