如何从异步Vec加入join_all

时间:2019-10-13 08:31:41

标签: rust async-await

我想生成一个Vec,然后用join_all执行它们

到目前为止,我已经尝试过此代码

#![feature(async_await)]
use futures::future::join_all;
use std::future::Future;

async fn hello(name: &str) -> String {
    format!("Hello {}!", name)
}

async fn main() {
    let urls = vec!["Peter", "Hans", "Jake"];
    let mut requests : Vec<Box<dyn Fn() -> Box<dyn Future<Output=String>>>> = vec![];
    for url in urls {
        requests.push(Box::new(|| Box::new(hello(&url))));
    }
    let responses : Vec<String>  = join_all(requests).await;

    println!("Response: {:?}", responses);
}

但是我收到以下错误消息。

error[E0277]: the trait bound `dyn std::ops::Fn() -> std::boxed::Box<dyn core::future::future::Future<Output = std::string::String>>: std::marker::Unpin` is not satisfied
   --> src/main.rs:15:45
    |
15  |     let responses : Vec<String>  = join_all(requests).await;
    |                                             ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn core::future::future::Future<Output = std::string::String>>`
    | 
   ::: /home/peter/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-preview-0.3.0-alpha.19/src/future/join_all.rs:118:14
    |
118 |     I::Item: Future,
    |              ------ required by this bound in `futures_util::future::join_all::join_all`
    |
    = note: required because of the requirements on the impl of `core::future::future::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn core::future::future::Future<Output = std::string::String>>>`

1 个答案:

答案 0 :(得分:1)

join_all需要期货的迭代器,而不是返回期货的函数的迭代器:

pub fn join_all<I>(i: I) -> JoinAll<<I as IntoIterator>::Item>
where
    I: IntoIterator,
    <I as IntoIterator>::Item: Future,

此外,您的期货无法固定,因此join_all无法使用它们。

最短的解决方法是:

  1. 致电关闭
  2. 确定未来
use futures::future; // 0.3.5
use std::{future::Future, pin::Pin};

async fn hello(name: &str) -> String {
    format!("Hello {}!", name)
}

pub async fn example() {
    let urls = vec!["Peter", "Hans", "Jake"];
    let mut requests: Vec<Box<dyn Fn() -> Pin<Box<dyn Future<Output = String>>>>> = vec![];
    for url in urls {
        requests.push(Box::new(move || Box::pin(hello(&url))));
    }
    let responses: Vec<String> = future::join_all(requests.into_iter().map(|r| r())).await;

    println!("Response: {:?}", responses);
}

这可以更简洁地写为:

use futures::future::{self, FutureExt, LocalBoxFuture}; // 0.3.5

async fn hello(name: &str) -> String {
    format!("Hello {}!", name)
}

pub async fn example() {
    let urls = vec!["Peter", "Hans", "Jake"];
    let mut requests: Vec<Box<dyn Fn() -> LocalBoxFuture<'static, String>>> = vec![];
    for url in urls {
        requests.push(Box::new(move || hello(&url).boxed_local()));
    }
    let responses: Vec<String> = future::join_all(requests.into_iter().map(|r| r())).await;

    println!("Response: {:?}", responses);
}

但是,对于您的特定示例,这些都不需要:

  1. 闭包没有任何价值
  2. 您只有一种类型的未来,因此无需动态调度
  3. 您甚至不需要Vec
use futures::future; // 0.3.5

async fn hello(name: &str) -> String {
    format!("Hello {}!", name)
}

pub async fn example() {
    let urls = vec!["Peter", "Hans", "Jake"];

    let hellos = urls.iter().map(|u| hello(u));
    let responses = future::join_all(hellos).await;

    println!("Response: {:?}", responses);
}

另请参阅: