作为函数指针类型的异步函数:正确的类型定义是什么?

Async function as a function pointer type: what is the correct type definition?

我有一组定义为

的处理程序
async fn handler1(req: Request<'_>, state: web::Data<State>) -> Result<HttpResponse, Error<'_>> {
    ...
}
async fn handler2(req: Request<'_>, state: web::Data<State>) -> Result<HttpResponse, Error<'_>> {
    ...
}

我正在尝试的是 return 从匹配语句指向此类处理程序的指针:

type MethodHandler = fn(req: Request<'_>, state: web::Data<State>) -> Result<HttpResponse, Error<'_>>;

fn select_handler(method: &str) -> Option<MethodHandler> {
    match method {
        "handler1" => Some(handler1),
        "handler2" => Some(handler2),
        _ => None
    }
}

由于处理程序的异步性质,它运行得不是很好:

error[E0308]: mismatched types
    --> src/handlers.rs:384:34
     |
1084 |         "handler1" => Some(handler1),
     |                                  ^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found opaque type
     |
     = note: expected fn pointer `for<'r> fn(handlers::Request<'r>, actix_web::web::Data<_>) -> std::result::Result<HttpResponse, handlers::Error<'r>>`
                   found fn item `for<'_> fn(handlers::Request<'_>, actix_web::web::Data<_>) -> impl futures_util::Future {handler1}`

error[E0308]: mismatched types
    --> src/handlers.rs:385:38
     |
1085 |         "handler1" => Some(handler1),
     |                                      ^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found opaque type
     |
     = note: expected fn pointer `for<'r> fn(handlers::Request<'r>, actix_web::web::Data<_>) -> std::result::Result<HttpResponse, handlers::Error<'r>>`
                   found fn item `for<'_> fn(handlers::Request<'_>, actix_web::web::Data<_>) -> impl futures_util::Future {handler2}`

所以我有两个问题:

  1. MethodHandler 的正确类型定义是什么?
  2. 也许我完全是想在这里发明轮子,并且已经有一些库/通用模式可以用于我正在尝试做的事情?

正如评论中指出的那样,每个 async 块和函数 return 都是您无法命名的匿名类型。虽然即使可以,但它们中的每一个都是独一无二的,因此无论如何您都无法拥有一个 return 类型。您将需要装箱期货并使用动态调度。

最简单的解决方案是 futures 板条箱中的 BoxFuture,它为您处理固定和生命周期。这将使您的类型定义

type MethodHandler = fn(req: Request<'_>, state: State)
                -> BoxFuture<Result<HttpResponse, Error<'_>>>;

并且您需要使用 FutureExt::boxed:

async 函数去糖化为 return 盒装未来
fn handler1(_req: Request<'_>, _state: State) -> BoxFuture<Result<HttpResponse, Error<'_>>> {
    async move {
        // Old function body
    }.boxed()
}

您可以在 this playground.

找到一个编译示例,虽然缺少真实类型