本文介绍了如何将异步函数放入 Rust 中的地图中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I cannot handle async functions when writing an async router for 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 好像有冲突,但是不知道怎么处理.

It seems there is a conflict between impl Future and dyn Future, but I have no idea how to handle it.

推荐答案

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

This happens because impl Future is a concrete unique type while dyn Future is an abstract type. HashMap expects the abstract type since it can only hold instances of a single type.

如果我们可以将异步函数的返回类型装箱,我们就可以将这些期货添加到 HashMap 中.

If we can box the return type of the async functions, we will able to add these futures into a HashMap.

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

First we need to change the type of 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

这个完整示例简化的FutureItem 类型,使用i32 而不是Result.另请查看 完整代码.

This complete examplesimplified Future's Item type, using an i32 instead of a Result. Please also check the full code for your case.

您还可以使用 futures crate 中的类型,例如 LocalBoxFutureBoxFutureFutureExt::boxedFutureExt::boxed_local 方法分别:

You can also use types from the futures crate like LocalBoxFuture and BoxFuture created by the FutureExt::boxed and FutureExt::boxed_local methods respectively:

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 中的地图中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 05:56