如何将Stream :: map与返回Result的函数一起使用?

时间:2019-02-23 12:58:22

标签: rust future

我有以下代码(请参阅playground):

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>,并且如果发生任何错误,则立即停止执行并从函数返回(例如,this example)?

注意:即使对于这个特定示例而言,use futures::Stream; // 0.1.25还是没有道理的。

2 个答案:

答案 0 :(得分:1)

下面的代码(playground link)是您对问题中当前代码的修改,可以得到您想要的结果:

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知道要将迭代器收集到的类型。

请注意,请勿将collect特性上的Iterator方法与collect上的Stream方法相混淆。

最后,虽然这可行,但它可能并不是您想要的,因为它仍然等待流中的所有结果收集到向量中,而在之前使用collect来转换向量。我没有期货方面的经验,所以不确定这种可能性如何(可能是,但是可能需要一个不太整齐的函数式编程风格的解决方案)。

答案 1 :(得分:0)

  

map,其函数返回Result

不要这样做,那不是您应该使用map的时候。而是使用and_then

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

在深入期货之前,您应该使用OptionResult和迭代器等更简单的Rust概念进行练习。许多概念转移了过来。

另请参阅: