在为hyper编写异步路由时,我无法处理异步函数.

此代码:

use std::collections::HashMap;
use std::future::Future;

type BoxedResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
type CalcFn = Box<dyn Fn(i32, i32) -> dyn Future<Output = BoxedResult<i32>>>;

async fn add(a: i32, b: i32) -> BoxedResult<i32> {
    Ok(a + b)
}

async fn sub(a: i32, b: i32) -> BoxedResult<i32> {
    Ok(a - b)
}

fn main() {
    let mut map: HashMap<&str, CalcFn> = Default::default();
    map.insert("add", Box::new(add));
    map.insert("sub", Box::new(sub));

    println!("map size: {}", map.len());
}

生成以下编译器错误:

error[E0271]: type mismatch resolving `<fn(i32, i32) -> impl std::future::Future {add} as std::ops::FnOnce<(i32, i32)>>::Output == dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
  --> src/main.rs:17:23
   |
17 |     map.insert("add", Box::new(add));
   |                       ^^^^^^^^^^^^^ expected opaque type, found trait std::future::Future
   |
   = note: expected type `impl std::future::Future`
              found type `dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
   = note: required for the cast to the object type `dyn std::ops::Fn(i32, i32) -> dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`

error[E0271]: type mismatch resolving `<fn(i32, i32) -> impl std::future::Future {sub} as std::ops::FnOnce<(i32, i32)>>::Output == dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
  --> src/main.rs:18:23
   |
18 |     map.insert("sub", Box::new(sub));
   |                       ^^^^^^^^^^^^^ expected opaque type, found trait std::future::Future
   |
   = note: expected type `impl std::future::Future`
              found type `dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
   = note: required for the cast to the object type `dyn std::ops::Fn(i32, i32) -> dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`

impl Futuredyn Future之间似乎有冲突,但我不知道如何处理.

推荐答案

这是因为impl Future是具体的唯一类型,而dyn Future是抽象类型.HashMap需要抽象类型,因为它只能保存单个类型的实例.

如果我们能够框选异步函数的返回类型,我们将能够将这些future 添加到HashMap中.

首先,我们需要改变CalcFn的类型:

type CalcFn = Box<dyn Fn(i32, i32) -> Pin<Box<dyn Future<Output = i32>>>>;

这样就可以做到:

let mut map: HashMap<&str, CalcFn> = Default::default();
map.insert("add", Box::new(|a, b| Box::pin(add(a, b))));
map.insert("sub", Box::new(|a, b| Box::pin(sub(a, b))));

println!("map size: {}", map.len());

//map.get("add").unwrap()(2, 3).await

这是complete example

您还可以使用futures crate 中的类型,例如分别由FutureExt::boxedFutureExt::boxed_local方法创建的LocalBoxFutureBoxFuture:

use futures::future::{FutureExt, LocalBoxFuture}; // 0.3.5
use std::collections::HashMap;

type BoxedResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
type CalcFn = Box<dyn Fn(i32, i32) -> LocalBoxFuture<'static, BoxedResult<i32>>>;

async fn add(a: i32, b: i32) -> BoxedResult<i32> {
    Ok(a + b)
}

async fn sub(a: i32, b: i32) -> BoxedResult<i32> {
    Ok(a - b)
}

async fn example() {
    let mut map: HashMap<&str, CalcFn> = Default::default();
    map.insert("add", Box::new(|a, b| add(a, b).boxed()));
    map.insert("sub", Box::new(|a, b| sub(a, b).boxed()));

    println!("map size: {}", map.len());

    //map.get("add").unwrap()(2, 3).await
}

Rust相关问答推荐

在特征中使用Async时,如何解决不透明类型`impl Future<;out=self>;`不满足其关联的类型边界和警告?

在Rust中有没有办法在没有UB的情况下在指针和U64之间进行转换?

如何用Axum/Tower压缩Html内容?

是否可以使用Rust宏来构建元组的项?

当对VEC;U8>;使用serde_json时,Base64编码是保护空间的好方法吗?

JSON5中的变量类型(serde)

为什么RefCell没有与常规引用相同的作用域?

具有多个键的 HashMap

Rust 中的内存管理

‘&T as *const T as *mut T’ 在 ‘static mut’ 项目中合适吗?

为什么不可变特征的实现可以是可变的?

使用自定义 struct 收集 Vec

为什么会出现无法移出可变引用后面的 `self.x`错误?

为什么分配对变量的引用使我无法返回它

为什么-x试图解析为文字并在声明性宏中失败?

有没有办法在 Rust 中对 BigInt 进行正确的位移?

如何在没有 `make_contiguous()` 的情况下对 VecDeque 进行排序或反转?

如果返回类型是通用的,我可以返回 &str 输入的一部分吗?

Rust 中的运行时插件

如何从 Rust 应用程序连接到 Docker 容器中的 SurrealDB?