6

I want to generate a Vec of .awaits and execute them with 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);
}

I get the error message:

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`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Peter
  • 81
  • 1
  • 6
  • You're creating the vec to hold boxes of closures returning boxes, but trying to add there pins of boxes of closures returning pins of boxes. What do you gen if you simply replace `Box::pin` with `Box::new`? – Cerberus Oct 13 '19 at 10:53
  • Thanks for the hint, then I get the error message (and others). I corrected my original post. – Peter Oct 13 '19 at 18:42

1 Answers1

2

join_all requires an iterator of futures, not an iterator of functions returning futures:

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

Additionally, your futures can't be pinned and so join_all cannot use them.

The shortest fix is to:

  1. Call the closure
  2. Pin the future
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);
}

This can be written more succinctly as:

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

However, none of that is needed for your specific example:

  1. The closure doesn't provide any value
  2. You have one type of future so there's no need for dynamic dispatch
  3. You don't even need a 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);
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366