Как я могу использовать Stream :: map с функцией, которая возвращает Result? - PullRequest
0 голосов
/ 23 февраля 2019

У меня есть следующий фрагмент кода (см. детская площадка ):

use futures::{stream, Future, Stream}; // 0.1.25
use std::num::ParseIntError;

fn into_many(i: i32) -> impl Stream<Item = i32, Error = ParseIntError> {
    stream::iter_ok(0..i)
}

fn convert_to_string(number: i32) -> Result<String, ParseIntError> {
    Ok(number.to_string())
}

fn main() {
    println!("start:");
    let vec = into_many(10)
        .map(|number| convert_to_string(number))
        .collect()
        .wait()
        .unwrap();

    println!("vec={:#?}", vec);

    println!("finish:");
}

Он выводит следующее (т.е. Vec<Result<i32, ParseIntError>>):

start:
vec=[
    Ok(
        "0"
    ),
    Ok(
        "1"
    ),
    Ok(
        "2"
    ), ...

Есть ли способ заставить его вывести Vec<i32> и, если произойдет какая-либо ошибка, немедленно прекратить выполнение и вернуться из функции (например, как в этом примере )?

Примечание : я хочу использовать use futures::Stream; // 0.1.25, даже если это не имеет смысла для этого конкретного примера.

Ответы [ 2 ]

0 голосов
/ 24 февраля 2019

map с функцией, которая возвращает Result

Не делайте этого, это не то, когда вы должны использовать map.Вместо этого используйте and_then:

let vec = into_many(10)
    .and_then(|number| convert_to_string(number))
    .collect()
    .wait()
    .unwrap();

Вы должны попрактиковаться с более простыми понятиями Rust, такими как Option, Result и итераторами, прежде чем погрузиться в будущее.Многие концепции переносятся.

См. Также:

0 голосов
/ 24 февраля 2019

Следующий код ( ссылка на игровую площадку ) как модификация вашего текущего кода в вашем вопросе дает желаемый результат:

use futures::{stream, Future, Stream}; // 0.1.25
use std::num::ParseIntError;

fn into_many(i: i32) -> impl Stream<Item = i32, Error = ParseIntError> {
    stream::iter_ok(0..i)
}

fn convert_to_string(number: i32) -> Result<String, ParseIntError> {
    Ok(number.to_string())
}

fn main() {
    println!("start:");
    let vec: Result<Vec<String>, ParseIntError> = into_many(10)
        .map(|number| convert_to_string(number))
        .collect()
        .wait()
        .unwrap()
        .into_iter()
        .collect();

    println!("vec={:#?}", vec);

    println!("finish:");
}

Поскольку ваш текущий код вернул Vecмы можем превратить это в итератор и собрать в нужный вам тип.Аннотации типов необходимы, чтобы сборщик знал, в какой тип собирать итератор.

Обратите внимание, что метод collect в признаке Iterator не следует путать с методом collect в Stream.

Наконец, хотя это работает, это может быть не совсем то, что вам нужно, поскольку он все еще ожидает сбора всех результатов из потока в вектор, за до с использованием команды collect.преобразовать вектор.У меня нет опыта работы с фьючерсами, поэтому я не уверен, насколько это возможно (возможно, но может потребоваться менее аккуратное решение в стиле функционального программирования).

...