如何使用将引用作为回调的 Rust 异步 fn?

s97*_*712 11 rust async-await

async fn返回一个实现 的匿名类型Future,因此如果我们想将它用作回调,我们需要将返回值转换为一个 trait 对象。

我试图编写一个函数来做到这一点,但我遇到了一些终身问题。

async fn将返回所有参数的生命周期,因此回调的签名也需要。如何将生命周期添加到回调的返回值中?

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)
}
Run Code Online (Sandbox Code Playgroud)

And*_*org 3

Rust 不支持更高种类的多态性,因此您需要向类型添加生命周期参数AsyncCb

\n\n
use futures::future::{Future, FutureExt, LocalBoxFuture};\n\ntype Context = ();\ntype AsyncCb<\'r> = Box<dyn FnOnce(&\'r Context) -> LocalBoxFuture<\'r, ()> + \'r>;\n\nfn normalize_async_cb<\'r, Fut: Future<Output = ()> + \'r>(f: fn(&\'r Context) -> Fut) -> AsyncCb {\n    let cb = move |ctx: &\'r Context| f(ctx).boxed_local();\n    Box::new(cb)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

此外,您可以Box通过返回impl特征来避免:

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

(如果需要,调用者可以使用Box::new(normalize_async_cb(\xe2\x80\xa6))as 类型AsyncCb。)

\n