Error handling Rust:从stdin读取和映射行,并处理不同的错误类型

Error handling Rust:从stdin读取和映射行,并处理不同的错误类型,error-handling,rust,idioms,Error Handling,Rust,Idioms,我正在学习Rust并试图用它解决一些基本的算法问题。在许多情况下,我希望从stdin中读取行,对每行执行一些转换,并返回结果项的向量。我这样做的一种方式是: //完全工作的防锈代码 让我的_值为:Vec=stdin .lock() .行() .filter_映射(结果::ok) .map(| line | line.parse::()) .filter_映射(结果::ok) .map(|x | x*2)//例如 .收集(); 这是可行的,但当然会忽略可能发生的任何错误。现在我想做的事情大致如下

我正在学习Rust并试图用它解决一些基本的算法问题。在许多情况下,我希望从stdin中读取行,对每行执行一些转换,并返回结果项的向量。我这样做的一种方式是:

//完全工作的防锈代码
让我的_值为:Vec=stdin
.lock()
.行()
.filter_映射(结果::ok)
.map(| line | line.parse::())
.filter_映射(结果::ok)
.map(|x | x*2)//例如
.收集();
这是可行的,但当然会忽略可能发生的任何错误。现在我想做的事情大致如下:

//伪ish代码
让我的值:Result=stdin
.lock()
.lines()//可能导致std::io::错误
.map(| line | line.parse::())//可以导致std::num::parseinteror
.map(|x | x*2)
.收集();
其中X是某种类型的错误类型,我可以在以后进行匹配。最好是一次在一行上执行整个操作,并在字符串数据被解析为int后立即丢弃它

我想我需要创建某种枚举类型来保存各种可能的错误,可能如下所示:

#[派生(调试)]
枚举输入程序{
Io(标准::Io::错误),
解析(std::num::parseinteror),
}
然而,我不太明白如何把所有的东西放在一起,使它干净,避免显式地匹配和到处施放。另外,是否有某种方法可以自动创建这些枚举错误类型,或者每次我都必须明确地枚举它们?

您的思路是正确的。 我的方法是使用您定义的枚举, 然后为您感兴趣的错误类型添加来自的
实现。
这将允许您在地图上使用
操作符来获得所需的行为

#[derive(Debug)]
enum MyError {
    IOError(std::io::Error),
    ParseIntError(std::num::ParseIntError),
}

impl From<std::io::Error> for MyError {
    fn from(e:std::io::Error) -> MyError {
        return MyError::IOError(e)
    }
}

impl From<std::num::ParseIntError> for MyError {
    fn from(e:std::num::ParseIntError) -> MyError {
        return MyError::ParseIntError(e)
    }
}

这将为您提供
Err(MyError(…)
Ok([1,2,3])


请注意,您可以通过使用错误处理板条箱(如
snafu
)来进一步减少一些错误样板,但在这种情况下,这并不太多。

作为替代方法,您可以通过将
my_值
声明为
Result
类型,作为
自动框错误来避免从
实现中写入
。另请参见:@asky-Yep,这也会起作用。但我认为,如果您想在以后进行更高级的错误处理,那么返回原始错误的具体类型可能会很棘手。(这可能是为什么有这么多错误处理板条箱的一个重要原因)。
let my_values: Vec<_> = stdin
    .lock()
    .lines()
    .map(|line| -> Result<u32,MyError> { Ok(line?.parse::<u32>()?*2) } )
    .collect();
let my_values: Result<Vec<_>,MyError> = stdin
    .lock()
    .lines()
    .map(|line| -> Result<u32,MyError> { Ok(line?.parse::<u32>()?*2) } )
    .collect();