如何从返回异步的闭包 Vec 中加入_all?

Pet*_*ter 5 rust async-await

我想要生成Vec.awaitS和与执行它们join_all

use futures::future::join_all; // 0.3.5
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);
}
Run Code Online (Sandbox Code Playgroud)

我收到错误消息:

error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` cannot be unpinned
  --> 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 futures::Future<Output = std::string::String>>`
   | 
  ::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/future/join_all.rs:83:14
   |
83 |     I::Item: Future,
   |              ------ required by this bound in `futures::future::join_all`
   |
   = note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`

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

error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` cannot be unpinned
  --> src/main.rs:15:36
   |
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 futures::Future<Output = std::string::String>>`
   | 
  ::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/future/join_all.rs:28:8
   |
28 |     F: Future,
   |        ------ required by this bound in `futures::future::JoinAll`
   |
   = note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`

error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
  --> src/main.rs:15:36
   |
15 |     let responses : Vec<String>  = join_all(requests).await;
   |                                    ^^^^^^^^^^^^^^^^^^ `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
   | 
  ::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/future/join_all.rs:28:8
   |
28 |     F: Future,
   |        ------ required by this bound in `futures::future::JoinAll`
   |
   = help: the trait `futures::Future` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
   = note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`

error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` cannot be unpinned
  --> src/main.rs:15:36
   |
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 futures::Future<Output = std::string::String>>`
   |
   = note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`

error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
  --> src/main.rs:15:36
   |
15 |     let responses : Vec<String>  = join_all(requests).await;
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
   |
   = help: the trait `futures::Future` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
   = note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`

error[E0277]: `main` has invalid return type `impl futures::Future`
 --> src/main.rs:9:17
  |
9 | async fn main() {
  |                 ^ `main` can only return types that implement `std::process::Termination`
  |
  = help: consider using `()`, or a `Result`

error[E0752]: `main` function is not allowed to be `async`
 --> src/main.rs:9:1
  |
9 | async fn main() {
  | ^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
Run Code Online (Sandbox Code Playgroud)

She*_*ter 2

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

pub fn join_all<I>(i: I) -> JoinAll<<I as IntoIterator>::Item>
where
    I: IntoIterator,
    <I as IntoIterator>::Item: Future,
Run Code Online (Sandbox Code Playgroud)

此外,您的期货无法固定,因此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);
}
Run Code Online (Sandbox Code Playgroud)

这可以更简洁地写为:

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);
}
Run Code Online (Sandbox Code Playgroud)

但是,您的具体示例不需要这些:

  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);
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: