error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:29:5
|
29 | Box::new(move |n| Box::pin(f(n)))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
Various efforts to resolve this have failed ... any ideas?
If you look at the whole error message, you'll see that rustc gives you an answer:
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:32:5
|
32 | Box::new(move |n| Box::pin(f(n)))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
28 | fn make_async_caller<F, T: Send + Sync + 'static>(f: fn(&mut T) -> F) -> ChainTask<T>
| +++++++++
For more information about this error, try `rustc --explain E0310`.
Add the 'static bound to T to make sure T only ever contains owned data and not any references that might not live long enough. Playground.
Thanks for the response - a case of not going far enough, then (I had tried 'static but was not convinced it would work or was correct - still trying to get my mind around exactly what 'static means! :))
As a matter of curiosity, would there be a solution where T could contain references - just asking makes me think it would be impossibly complex though!
I find that Rust by Example has a good definition of the 'static trait bound:
Took me a little to get the bounds right (forgot to add it to the dyn Fn type in ChainTask), but you can pull it off (if this is actually usable, I don't know). Playground.
We need to make the lifetime of the mutable reference to T explicit as well, because the closure can never outlive that argument. Furthermore, the function now can not outlive the lifetime of the &'b mut T we pass to our function pointer, instead of the lifetime 'a we added as a bound to T. Lastly, we must make sure that 'a outlives 'b (otherwise we could pass dangling pointers inside of T), so we need to add the 'a: 'b bound. Playground.
As a bound, it means "doesn't contain references shorter than 'static", or equivalently, "valid to store for the 'static lifetime".
(As the parameter of a reference, it means something completely different — it means that the referent actually lives for the 'static lifetime, ie. forever.)
At this point I don't believe you can pull it off with lifetimes. At least I can't. We'd need HRTBs to express that our tasks don't take ownership for the explicit lifetime 'b of our TestContext instance, but only for some unspecified lifetime (the lifetime of the given loop iteration). But our task functions are not actually implemented for any lifetime 'b, but only for lifetimes 'b that don't outlive'a (the lifetime of T). Lifetime bounds are currently not supported in HRTBs (there's an open RFC to implement that feature). So without making T'static to get rid of 'a, I don't think we can get your program to compile.
Well, I'm very glad that I came to that conclusion too - though by much less rigorous thought than your own. I actually have an "owned" version working, where each task takes ownership of the context and then returns it. But that's messy when dealing with errors, which the task functions have to handle "specially". I guess that's what I'm stuck with at the moment, then!
Yeah I agree that this is not ideal when working with Result. Alternatively you can wrap your context in an Arc<Mutex<T>> and pass that to each task. Playground.