What is the concrete type of a future returned fro

2020-03-26 18:16发布

问题:

What type should I use for a vector that stores futures?

I tried to make multiple concurrent requests on the same URL and save all the futures into the vector to use with join_all.

If I don't set a type for the vector explicitly, everything works. I understand that Rust can find the proper type of a variable. CLion determines the vector type as Vec<dyn Future<Output = ()>>, but when I try to set the type by myself, it gives me an error:

error[E0277]: the size for values of type `dyn core::future::future::Future<Output = ()>` cannot be known at compilation time
  --> src/lib.rs:15:23
   |
15 |     let mut requests: Vec<dyn Future<Output = ()>> = Vec::new();
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `dyn core::future::future::Future<Output = ()>`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required by `std::vec::Vec`

I must declare the type as Vec<Pin<Box<dyn Future<Output=()>>>> which forces me to wrap result of function into requests.push(Pin::from(Box::new(request(i))));

use futures::future::join_all;
use std::future::Future;
use std::pin::Pin;

async fn request(n: i32) {
    println!("Started: {}", n);
    let response = reqwest::get("https://www.rust-lang.org")
        .unwrap()
        .text()
        .unwrap();
    println!("Completed: {}. Response: {}", n, &response[0..10]);
}

async fn main() {
    let mut requests: Vec<dyn Future<Output = ()>> = Vec::new();
    for i in 0..5 {
        requests.push(request(i));
    }
    join_all(requests).await;
}

Which type it should be?

回答1:

From the RFC:

The return type of an async function is a unique anonymous type generated by the compiler, similar to the type of a closure. You can think of this type as being like an enum, with one variant for every "yield point" of the function - the beginning of it, the await expressions, and every return. Each variant stores the state that is needed to be stored to resume control from that yield point.

When the function is called, this anonymous type is returned in its initial state, which contains all of the arguments to this function.

You can't explicitly declare the concrete type of a future since it is an anonymous type. As an API user we only need to know that it implements std::futures::Future but this doesn't mean that we don't need a deeper knowledge of this anonymous type and it's implementation, it would be nice to have for grasping the concept.


CLion determines the vector type as Vec<dyn Future<Output = ()>>

This is a type hint, not the actual type, since compiler is not able to know the size of dyn Future<Output = ()>, it will not be compiled.


Pin<Box<_>>-ing a Future to declare an explicit type might not be a good idea. In your case it's not needed because the concrete types returned from async fn are identical. Letting the compiler infer the type will just be fine.

See also:

  • For various concrete return types : How can I put an async function into a map in Rust?
  • Static & Dynamic dispatch : Trait Objects