Search code examples
asynchronousrustasync-awaitclosuresfuture

How to accept an async function as an argument?


I would like to replicate the behavior and ergonomics of taking a closure/function as an argument much like map does: iterator.map(|x| ...).

I've noticed that some library code allows passing in async functionality, but this method doesn't allow me to pass in arguments:

pub fn spawn<F, T>(future: F) -> JoinHandle<T>
where
    F: Future<Output = T> + Send + 'static,
    T: Send + 'static,
spawn(async { foo().await });

I'm hoping to do one of the following:

iterator.map(async |x| {...});
async fn a(x: _) {}
iterator.map(a)

Solution

  • async functions are effectively desugared as returning impl Future. Once you know that, it's a matter of combining existing Rust techniques to accept a function / closure, resulting in a function with two generic types:

    use std::future::Future;
    
    async fn example<F, Fut>(f: F)
    where
        F: FnOnce(i32, i32) -> Fut,
        Fut: Future<Output = bool>,
    {
        f(1, 2).await;
    }
    

    This can also be written as

    use std::future::Future;
    
    async fn example<Fut>(f: impl FnOnce(i32, i32) -> Fut)
    where
        Fut: Future<Output = bool>,
    {
        f(1, 2).await;
    }