Почему реализация итератора не достаточно универсальна c в контексте asyn c? - PullRequest
4 голосов
/ 29 апреля 2020

Перекрестная публикация на github

Учитывая следующий фрагмент:

use futures::stream::{self, StreamExt};

async fn from_bar(bar: &[Vec<&u8>]) {
    let x = bar.iter().flat_map(|i| i.iter().map(|_| async { 42 }));
    let foo: Vec<_> = stream::iter(x).collect().await;
}

#[tokio::main]
async fn main() {
    for bar in vec![] {
        tokio::spawn(async {
            from_bar(bar).await;
        });
    }
}

Я получаю следующие ошибки:

error[E0308]: mismatched types
  --> src/main.rs:11:9
   |
11 |         tokio::spawn(async {
   |         ^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected type `std::ops::FnOnce<(&&u8,)>`
              found type `std::ops::FnOnce<(&&u8,)>`

error: implementation of `std::iter::Iterator` is not general enough
    --> src/main.rs:11:9
     |
11   |           tokio::spawn(async {
     |           ^^^^^^^^^^^^ implementation of `std::iter::Iterator` is not general enough
     |
     = note: `std::iter::Iterator` would have to be implemented for the type `std::slice::Iter<'0, &u8>`, for any lifetime `'0`...
     = note: ...but `std::iter::Iterator` is actually implemented for the type `std::slice::Iter<'1, &u8>`, for some specific lifetime `'1`

Я не ожидал ошибки, потому что время жизни мне кажется правильным. Обратите внимание, что удаление main() или удаление кода внутри from_bar() обоих устраняет ошибки. Мало того, сообщения об ошибках также очень странные. Они могут быть связаны с регрессией в компиляторе , хотя, скорее всего, они находятся не в том месте ( может быть связано ).

Версия rustc 1.43.0 (4fb7144ed 2020-04-20) :

[dependencies]
futures = '0.3.1'

[dependencies.tokio]
version = '0.2'
features = ['full']

1 Ответ

0 голосов
/ 29 апреля 2020

Немного более простое воспроизведение:

use futures::stream::{self, StreamExt};

async fn from_bar(bar: &[Vec<&u8>]) {
    let x = bar.iter().flat_map(|i| i.iter().map(|_| async { 42 }));
    let foo: Vec<_> = stream::iter(x).collect().await;
}

#[tokio::main]
async fn main() {
    tokio::spawn(async {
        from_bar(&vec![]).await;
    });
}

детская площадка .

Этот пример проясняет, что не так: ссылка, которую вы передаете на from_bar, действует только до тех пор, пока конец main (или, возможно, даже текущей итерации l oop в вашем примере), но для spawn необходимо, чтобы она дольше проживала, поскольку порожденная задача может выполняться дольше.

Что я не делаю Я не понимаю, как это переводится в сообщение об ошибке, которое мы получаем ...

...