Как выбрать или объединить фьючерсы с разными типами?

#rust

#Ржавчина

Вопрос:

У меня есть общая асинхронная функция. Я хочу вызвать его с разными типами и запустить полученные фьючерсы параллельно. Но похоже, что он создает фьючерсы разных типов (хотя все они являются impl Future<Output=()> ) , поэтому я не могу помещать объекты разных типов в вектор, поэтому я не могу вызвать функцию выбора. Вот что я имею в виду:

 use std::fmt::Debug;

#[tokio::main]
async fn main() {
    // both arguments to test function i32. Works.
    let first = Box::pin(test(5));
    let second =  Box::pin(test(6));
    futures::future::select_all(vec![first, second]).await;
}

async fn test<T: Debug>(x: T) {
    async {
        println!("{:?}", x);
    }.await;
}
  

И это не работает:

 use std::fmt::Debug;

#[tokio::main]
async fn main() {
    // one argument to test() is i32, the second argument is amp;str. Doesn't work
    let first = Box::pin(test(5));
    let second =  Box::pin(test("five"));
    futures::future::select_all(vec![first, second]).await;
}

async fn test<T: Debug>(x: T) {
    async {
        println!("{:?}", x);
    }.await;
}
  

В моем конкретном примере я могу использовать select, который принимает два фьючерса, но что, если у меня много фьючерсов? Как я могу выбрать несколько фьючерсов с разными типами?

Ответ №1:

вам просто нужно немного помочь компилятору определить правильный тип. Здесь мы используем динамическую диспетчеризацию с dyn ключевым словом.

 use std::fmt::Debug;
use std::pin::Pin;

#[tokio::main]
async fn main() {
    // one argument to test() is i32, the second argument is amp;str.
    let first = Box::pin(test(5));
    let second = Box::pin(test("five"));
    let v: Vec<Pin<Box<dyn futures::Future<Output = ()>>>> = vec![first, second];
    futures::future::select_all(v).await;
}

async fn test<T: Debug>(x: T) {
    async {
        println!("{:?}", x);
    }
    .await;
}
  

Итак, все, что я сделал, это извлек вектор в переменную и присвоил ему явный тип.