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) 
3

3 Answers

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; } 
2

The async |...| expr closure syntax is available on the nightly channel enabling the feature async_closure.

#![feature(async_closure)] use futures::future; use futures::Future; use tokio; pub struct Bar; impl Bar { pub fn map<F, T>(&self, f: F) where F: Fn(i32) -> T, T: Future<Output = Result<i32, i32>> + Send + 'static, { tokio::spawn(f(1)); } } async fn foo(x: i32) -> Result<i32, i32> { println!("running foo"); future::ok::<i32, i32>(x).await } #[tokio::main] async fn main() { let bar = Bar; let x = 1; bar.map(foo); bar.map(async move |x| { println!("hello from async closure."); future::ok::<i32, i32>(x).await }); } 

See the 2394-async_await RFC for more detalis

It's too late but I hope this code helps others. In my situation I have some predefined functions which I can not change them (func0, func1, ...) and I need to run them all till the last one in order. If one fails, the whole operation must terminate. So I created an array of functions, then each item will get executed during a loop.

use std::future::Future; use std::pin::Pin; type FuncResult = dyn Future<Output=Result<(), String>>; async fn apply_funcs(mut start: usize, end: usize) { let funcs = [func0]; let mut result = true; while start < end && result { result = func_wrapper(funcs[start]).await; start += 1; } } async fn func_wrapper(f: impl FnOnce() -> FuncResult) -> bool { match f().await { Ok(_) => { println!("ok"); } Err(e) => { println!("{e}"); return false; } } true } async fn func0() -> Result<(), String> { todo!() } 

This code fails: expected dyn Future, found future

I found 2 ways to solve that:

1: By static dispatching which is by generics:

async fn apply_funcs(mut start: usize, end: usize) { let funcs = [func0]; let mut result = true; while start < end && result { result = func_wrapper(funcs[start]).await; start += 1; } } async fn func_wrapper<Fut>(f: impl FnOnce() -> Fut) -> bool where Fut: Future<Output=Result<(), String>> { match f().await { Ok(_) => { println!("ok"); } Err(e) => { println!("{e}"); return false; } } true } async fn func0() -> Result<(), String> { todo!() } 

2: By dynamic dispatching via defining another closure:

type FuncResult = Pin<Box<dyn Future<Output=Result<(), String>>>>; async fn apply_funcs(mut start: usize, end: usize) { let funcs = [ || -> FuncResult { Box::pin(func0())// no await here } ]; let mut result = true; while start < end && result { result = func_wrapper(funcs[start]).await; start += 1; } } async fn func_wrapper(f: impl FnOnce() -> FuncResult) -> bool { match f().await { Ok(_) => { println!("ok"); } Err(e) => { println!("{e}"); return false; } } true } async fn func0() -> Result<(), String> { todo!() } 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.