How to pass asynchronous functions as parameters to other functions

async fn func(num: &mut usize) -> Result<String, _>
{
    println!("func{}", num);
    Ok("".to_string())
}
pub fn funcs<F>(func:F) 
    {
       ....
    }

I know how to pass' fn ', but how to handle' fn ->Future 'with' asynchronous'

Maybe this works for you:

use std::future::Future;

async fn func(num: &mut usize) -> Result<String, ()> {
    println!("func{}", num);
    Ok("".to_string())
}

pub fn funcs<'a, F, Fut>(_func: F)
where
    F: Fn(&'a mut usize) -> Fut,
    Fut: Future<Output = Result<String, ()>>,
{
}

fn main() {
    funcs(func);
}

Playground.

2 Likes
...
type PinFutureObjWithLife<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
pub type ItemWithLife = Box<dyn for<'a> Fn(&'a mut usize) -> PinFutureObjWithLife<'a, ()>>;
...
pub fn funcs<'a, F, Fut>(_func: F)
where
    F: Fn(&'a mut usize) -> Fut,
    Fut: Future<Output = Result<String, ()>>,
{
 let mut vec = Vec::<ItemWithLife>::new();
 vec.push(Box::new(|num| Box::pin(handle(num))));
}

I want to store the handle in vec
err:

borrowed data escapes outside of closure
argument requires that `'1` must outlive `'a`

What should I do?
Thank you.

You might be able to get a more satisfying answer if you could tell us exactly what you are after and provide us with a minimal reproducible example. I have no idea what you really want to achieve based on your snippet, nor can I reproduce the error you posted.

...
pub struct Llt {
    router_map: Option<Vec<ItemWithLife>>,
}
impl Llt {
pub fn add_router<F, Fut>(&mut self,msg_id:usize,handle: F) 
    where
        F: Fn(usize) -> Fut + Send + 'static,
        Fut: Future<Output = WorkerResult>+ Send + 'static,
    {
        let mut vec = Vec::<ItemWithLife>::new();
        vec.push(Box::new(|num| Box::pin(handle(num))));
        self.router_map = vec;
    }
}
pub fn build() -> Self {
        Llt {
            router_map: None,
        }
    }
...
type PinFutureObjWithLife<T> = Pin<Box<dyn Future<Output = T>>>;
pub type ItemWithLife = Box<dyn Fn(usize) -> PinFutureObjWithLife<WorkerResult>>;
...
async fn func(num:usize) -> WorkerResult
{
    println!("func1_without_ref-{}", num);
    Ok("".to_string())
}
pub type WorkerResult<T = String, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
...
#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn it_works() {
        let mut llt = Llt::build();
        llt.add_router(1, func);
    }
}

I want to customize a struct to store fn, just like how axum and actix_web define a route
But Axum and Actix_web use some advanced macros, and I haven't learned anything about macros yet, as in the code above. I want to use this method to save fn in my router_map and retrieve it when needed

It's basically just missing a move before the closure to make sure the handle is captured by value:

use futures::future::{BoxFuture, Future};

pub struct Llt<'a> {
    router_map: Vec<ItemWithLife<'a>>,
}

impl<'a> Llt<'a> {
    pub fn add_router<F, Fut>(&mut self, handle: F)
    where
        F: Fn(usize) -> Fut + 'static,
        Fut: Future<Output = WorkerResult> + Send + 'a,
    {
        self.router_map
            .push(Box::new(move |num| Box::pin(handle(num))));
    }

    pub fn build() -> Self {
        Llt {
            router_map: Vec::new(),
        }
    }
}

pub type ItemWithLife<'a> = Box<dyn Fn(usize) -> BoxFuture<'a, WorkerResult>>;
pub type WorkerResult<T = String, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;

#[cfg(test)]
mod tests {
    use super::*;

    async fn func(num: usize) -> WorkerResult {
        println!("func1_without_ref-{}", num);
        Ok("".to_string())
    }

    #[tokio::test]
    async fn it_works() {
        let mut llt = Llt::build();
        llt.add_router(func);
    }
}

Playground.

2 Likes

It succeeded, thank you very much. Your personal homepage is great, and good luck to you :+1: :+1: :+1:

1 Like