Come posso inserire una funzione asincrona in una mappa in Rust?


11

Non riesco a gestire le funzioni asincrone durante la scrittura di un router asincrono hyper.

Questo codice:

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

Genera il seguente errore del compilatore:

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>>>`

Sembra che ci sia un conflitto tra impl Futuree dyn Future, ma non ho idea di come gestirlo.

Risposte:


5

Questo accade perché impl Futureè un tipo unico concreto mentre dyn Futureè un tipo astratto. HashMapsi aspetta il tipo astratto poiché può contenere solo istanze di un singolo tipo.

Se riusciamo a inserire il tipo di ritorno delle funzioni asincrone, saremo in grado di aggiungere questi future in a HashMap.

Innanzitutto dobbiamo cambiare il tipo di CalcFn:

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

Quindi questo può fare il trucco:

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

Questo esempio completo ha semplificato Futureil Itemtipo, usando un i32invece di a Result. Controlla anche il codice completo per il tuo caso .


Esempio completo con esecutore
Ömer Erden,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.