How to use a Rust async fn that takes a reference as a callback?

喜夏-厌秋 提交于 2020-02-20 07:35:06

问题


async fn returns an anonymous type that implements Future, so if we want to use it as a callback, we need to convert the return value to a trait object.

I tried to write an function to do this, but I had some lifetime problems.

async fn will return lifetime of all parameters, so the signature of callback also needs to. How can I add the lifetime to the return value of the callback?

use futures::future::{Future, FutureExt, LocalBoxFuture};

type Context = ();
type AsyncCb = Box<dyn for<'r> FnOnce(&'r Context) -> LocalBoxFuture<'r, ()>>;

fn normalize_async_cb<Fut: Future<Output = ()>>(f: for<'r> fn(&'r Context) -> Fut) -> AsyncCb
//                                                    how to add 'r for Fut?  ^^^
{
    let cb = move |ctx: &Context| f(ctx).boxed_local();
    Box::new(cb)
}

回答1:


Rust does not support higher-kinded polymorphism, so you need to add a lifetime parameter to the AsyncCb type:

use futures::future::{Future, FutureExt, LocalBoxFuture};

type Context = ();
type AsyncCb<'r> = Box<dyn FnOnce(&'r Context) -> LocalBoxFuture<'r, ()> + 'r>;

fn normalize_async_cb<'r, Fut: Future<Output = ()> + 'r>(f: fn(&'r Context) -> Fut) -> AsyncCb {
    let cb = move |ctx: &'r Context| f(ctx).boxed_local();
    Box::new(cb)
}

Aditionally, you can avoid a Box by returning impl trait:

fn normalize_async_cb<'r, Fut: Future<Output = ()> + 'r>(
    f: fn(&'r Context) -> Fut,
) -> impl FnOnce(&'r Context) -> LocalBoxFuture<'r, ()> {
    let cb = move |ctx: &'r Context| f(ctx).boxed_local();
    cb
}

(The caller can then use Box::new(normalize_async_cb(…)) as type AsyncCb if desired.)



来源:https://stackoverflow.com/questions/58891121/how-to-use-a-rust-async-fn-that-takes-a-reference-as-a-callback

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!