Какой конкретный тип будущего возвращается из `async fn`? - PullRequest
2 голосов
/ 08 ноября 2019

Какой тип я должен использовать для вектора, в котором хранятся фьючерсы?

Я пытался сделать несколько одновременных запросов на один и тот же URL и сохранить все фьючерсы в векторе для использования с join_all.

Если я не установлю тип для вектора явно, все будет работать. Я понимаю, что Rust может найти правильный тип переменной. CLion определяет тип вектора как Vec<dyn Future<Output = ()>>, но когда я пытаюсь установить тип самостоятельно, он выдает мне ошибку:

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`

Я должен объявить тип как Vec<Pin<Box<dyn Future<Output=()>>>>, что заставляет меня обернутьрезультат функции в 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;
}

Какого типа это должно быть?

1 Ответ

1 голос
/ 08 ноября 2019

Из RFC :

Тип возвращаемого значения асинхронной функции - это уникальный анонимный тип, сгенерированный компилятором, аналогичный типу замыкания. Вы можете думать об этом типе как о перечислении, с одним вариантом для каждого «предела текучести» функции - его начала, выражений ожидания и каждого возврата. Каждый вариант хранит состояние, которое необходимо сохранить, чтобы возобновить управление с этого предела доходности.

Когда вызывается функция, этот анонимный тип возвращается в исходное состояние, которое содержит все аргументы этой функции. .

Вы не можете явно объявить конкретный тип будущего, поскольку это анонимный тип. Как пользователь API, нам нужно только знать, что он реализует std::futures::Future, но это не значит, что нам не нужны более глубокие знания этого анонимного типа и его реализации, было бы неплохо иметь представление о концепции.


CLion определяет тип вектора как Vec<dyn Future<Output = ()>>

Это подсказка типа, а не фактический тип, так как компилятор не может знать размерdyn Future<Output = ()>, он не будет скомпилирован.


Pin<Box<_>> -ing Future для объявления явного типа не очень хорошая идея. В вашем случае вам даже не нужно этого делать, потому что конкретные типы, возвращаемые из async fn, одинаковы. Позволить компилятору сделать вывод, что с типом все будет в порядке.

См. Также:

Для различных конкретных типов возврата: Как поместить асинхронную функцию вкарта в Rust?

Статическая и динамическая отправка: Объекты черты

...