асинхронная функция хранения вектора ржавчины не может использовать `impl Future` - PullRequest
1 голос
/ 12 октября 2019

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

приведенный ниже код не скомпилируется, потому что для типа вектора

ошибка:impl Trait не допускается за пределами функции и встроенного метода возвращаемые типы

версия ржавчины по ночам 1.40.0

use std::future::Future;

fn main(){
    let mut v: Vec<fn()->impl Future<Output=()>> = vec![];

    v.push(haha);
}

async fn haha(){
    println!("haha");
}

Не могли бы вы сказать, как написать тип внутри вектора?

Большое спасибо !!!

PS: я обнаружил, что, возможно, есть обходной путь с использованием type, поэтому я изменил код ниже

use std::future::Future;

type Haha = impl Future<Output=()>;

fn main(){
    let mut v: Vec<fn()->Haha> = vec![];

    v.push(haha);
}

async fn haha(){
    println!("haha");
}

, который тоже не работает,На этот раз ошибка возникает в псевдониме типа Rust говорит:

error: could not find defining uses
 --> src\main.rs:5:1
  |
5 | type Haha = impl Future<Output=()>;
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Как это исправить ???

1 Ответ

1 голос
/ 12 октября 2019

Вы не можете использовать impl Trait таким образом. Чтобы иметь возможность хранить различные типы, которые реализуют признак, в одном и том же контейнере, вы должны использовать динамическую диспетчеризацию, сохраняя что-то вроде Box<dyn Trait>.

. В вашем конкретном случае вы не указываете, хотите ли вы сохранитьСами асинхронные функции или будущее, сгенерированное асинхронными функциями, решение будет несколько другим.

Чтобы хранить только фьючерсы, вы пишете контейнер, такой как:

let mut v: Vec<Box<dyn Future<Output=()>>> = vec![];

И затем простовызовите функцию, поместите ее в коробку и сохраните в контейнере:

v.push(Box::new(haha()));

Если вместо этого вы хотите сохранить саму асинхронную функцию, не вызывая ее, вам нужен контейнер с двойным dyn:

let mut v2: Vec<Box<dyn Fn() -> Box<dyn Future<Output=()>>>> = vec![];

Теперь, поскольку ваша функция haha не реализует эту черту Fn, вам нужен адаптер. Лямбда-функция будет работать просто замечательно, и не забудьте двойное Box:

v2.push(Box::new(|| Box::new(haha())));

ОБНОВЛЕНИЕ:

К сожалению, с этими решениями вы будетев состоянии создать вектор, но не .await для вашего будущего. Для этого вам понадобится фьючерс на реализацию маркера Unpin. Это гарантирует компилятору, что будущее не будет перемещено во время его работы, потому что это будет совершенно небезопасно. Вы можете добавить требование + Unpin к фьючерсу, но async fn не равно Unpin, поэтому вы не можете заполнить вектор. Самый простой способ исправить это - использовать эту удобную функцию из std:

pub fn into_pin(boxed: Box<T>) -> Pin<Box<T>>

for f in v2 {
    f().into_pin().await;
}

К сожалению, она все еще нестабильна. К счастью, есть From impl, который делает то же самое. Так что вы можете просто написать:

for f in v2 {
    Pin::from(f()).await;
}

PS : В своем комментарии ниже вы напишите этот код, чтобы дождаться фьючерса:

for f in v2 {
    async { f().await }
}

Обратите внимание, что *Сам блок 1050 * оценивает другое будущее, поэтому здесь вы просто заключаете каждое будущее в другое будущее, но никто его не ждет. На самом деле вы получите предупреждение об этом:

предупреждение: неиспользуемый реализатор std::future::Future, который необходимо использовать.

Помните, что для правильного ожидания всехфьючерсы вам понадобится асинхронная среда выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...