Jak korzystać z async fn Rust, który przyjmuje odwołanie jako wywołanie zwrotne?

10

async fnzwraca anonimowy typ, który implementuje Future, więc jeśli chcemy użyć go jako wywołania zwrotnego, musimy przekonwertować wartość zwracaną na obiekt cechy.

Próbowałem napisać funkcję, aby to zrobić, ale miałem pewne problemy życiowe.

async fnzwróci czas życia wszystkich parametrów, więc podpis wywołania zwrotnego również musi. Jak mogę dodać czas życia do wartości zwrotnej wywołania zwrotnego?

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)
}
s97712
źródło
Dlaczego dane wejściowe do normalize_async_cbwskaźnika funkcji?
Coder-256
Co również rozumiesz przez „oddzwanianie”? Czy możesz podać przykład pokazujący, gdzie potrzebujesz tego rodzaju oddzwonienia?
Coder-256

Odpowiedzi:

1

Rdza nie obsługuje polimorfizmu wyższego rodzaju, dlatego należy dodać parametr lifetime do AsyncCbtypu:

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

Dodatkowo możesz uniknąć Box, zwracając implcechę:

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
}

(W razie potrzeby dzwoniący może użyć Box::new(normalize_async_cb(…))jako typu AsyncCb).

Anders Kaseorg
źródło