First of all, a small fix of your syntax
:
async fn test_ref<F>(f: F) // Attempt 2
where
- for<'a> F: FnOnce(&'a Token) -> BoxFuture<()> + 'a,
+ for<'a> F: FnOnce(&'a Token) -> BoxFuture<'a, ()>,
{
let token = Token();
f(&token).await;
}
And from there, you get a "'static not satisfied" error, regarding which you may want to read:
Basically you have been correctly using for<'a> quantification to be able to handle the lifetime of the borrow to your local / interior token variable ("infinitely small lifetimes"), but sadly, for<…>, by itself, conveys to Rust that you also want the caller to be able to handle "infinitely big lifetimes" such as 'static.
One way to fix that is to also introduce the hack showcased in the aforementioned post:
- async fn test_ref< F>(f: F) // Attempt 2
+ async fn test_ref<'up, F>(f: F) // Attempt 2
where
- for<'a> F: FnOnce(&'a Token) -> BoxFuture<'a, ()>,
+ for<'a> F: FnOnce(&'a Token, [&'a &'up (); 0]) -> BoxFuture<'a, ()>,
{
let token = Token();
- f(&token).await;
+ f(&token, []).await;
}
together with, at the call site:
- test_ref(|token: &Token| async move {
+ test_ref(|token: &Token, []| async move {
string.push('b');
println!("{:?}", token);
}.boxed())
.await;
Playground
Note that if you control the definition of Token, you could smuggle the 'upper bound lifetime in there, and thus avoid exposing that [] hack to the callers:
#[derive(Debug)]
struct Token<'up>(::core::marker::PhantomData<&'up ()>);
async fn test_ref<'up, F>(f: F) // Attempt 2
where
for<'a> F: FnOnce(&'a Token<'up>) -> BoxFuture<'a, ()>,
{
let token = Token(<_>::default());
f(&token).await;
}