【问题标题】:How can I put an async function into a map in Rust?如何将异步函数放入 Rust 中的地图?
【发布时间】:2019-11-05 04:15:39
【问题描述】:

在为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 之间似乎有冲突,但我不知道如何处理。

【问题讨论】:

    标签: rust async-await


    【解决方案1】:

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

    如果我们可以将异步函数的返回类型装箱,我们将能够将这些期货添加到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 简化了FutureItem 类型,使用i32 而不是Result。另请查看full code for your case

    您还可以使用期货箱中的类型,例如分别由 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
    }
    
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-22
    • 1970-01-01
    相关资源
    最近更新 更多