Another way to store an async function is with trait objects. This is useful if you want to be able to swap out the function dynamically at runtime, or store a collection of async functions. To do this, we can store a boxed Fn that returns a boxed Future:
use futures::future::BoxFuture; // Pin<Box<dyn Future<Output = T> + Send>>
struct S {
    foo: Box<dyn Fn(u8) -> BoxFuture<'static, u8>,
}
However, if we try to initialize S, we immediately run into a problem:
async fn foo(x: u8) -> u8 {
    x * 2
}
let s = S { foo: Box::new(foo) };
error[E0271]: type mismatch resolving `<fn(u8) -> impl futures::Future {foo} as FnOnce<(u8,)>>::Output == Pin<Box<(dyn futures::Future<Output = u8> + 'static)>>`
  --> src/lib.rs:14:22
   |
5  | async fn foo(x: u8) -> u8 {
   |                        -- the `Output` of this `async fn`'s found opaque type
...
14 |     let s = S { foo: Box::new(foo) };
   |                      ^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
   |
   = note: expected struct `Pin<Box<(dyn futures::Future<Output = u8> + 'static)>>`
           found opaque type `impl futures::Future`
The error message is pretty clear. S expects a owned Future, but async functions return impl Future. We need to update our function signature to match the stored trait object:
fn foo(x: u8) -> BoxFuture<'static, u8> {
    Box::pin(async { x * 2 })
}
That works, but it would be a pain to Box::pin in every single function we want to store. And what if we want to expose this to users?
We can abstract the boxing away by wrapping the function in a closure:
async fn foo(x: u8) -> u8 {
    x * 2
}
let s = S { foo: Box::new(move |x| Box::pin(foo(x))) };
(s.foo)(12).await // => 24
This works fine, but we can make it even nicer by writing a custom trait and performing the conversion automagically:
trait AsyncFn {
    fn call(&self, args: u8) -> BoxFuture<'static, u8>;
}
And implement it for the function type we want to store:
impl<T, F> AsyncFn for T
where
    T: Fn(u8) -> F,
    F: Future<Output = u8> + 'static,
{
    fn call(&self, args: u8) -> BoxFuture<'static, u8> {
        Box::pin(self(args))
    }
}
Now we can store a trait object of our custom trait!
struct S {
    foo: Box<dyn AsyncFn>,
}
let s = S { foo: Box::new(foo) };
s.foo.call(12).await // => 24
, how to specify the return type ? Vec– Charlie 木匠 Oct 28 '22 at 22:14is not working, it complains `Output ...`. Could you have a return type example ?