在 Rust 中使用 and_then 有条件地对特定错误采取行动

Conditionally Acting on Specific Error Using and_then in Rust

我如何知道在 Rust 中通过 and_then 管道 Results 时发生了什么错误?例如,使用嵌套匹配我可以这样做:

use std::num::ParseIntError;

fn get_num(n: u8) -> Result<u8, ParseIntError> {
   // Force a ParseIntError
   "foo ".parse()
}
fn add_one(n: u8) -> Result<u8, ParseIntError> {
    Ok(n + 1)
}
fn main() {
    match get_num(1) {
        Ok(n) => {
            match add_one(n) {
                Ok(n) => println!("adding one gives us: {}", n),
                Err(why) => println!("Error adding: {}", why)
            }
        },
        Err(why) => println!("Error getting number: {}", why),
    }
}

或者我可以使用 and_then 将第一个函数的结果通过管道传递给第二个并避免嵌套匹配:

match get_num(1).and_then(add_one) {
  Ok(n) => println!("Adding one gives us: {}", n),
  Err(why) => println!("Some error: {}.", why)
}

如何使用 and_then 有条件地和惯用地确定第二种形式中的错误?我必须键入检查错误吗?当然,我可以像上面那样显示错误,但假设我想在它前面加上与错误类型相关的内容?

通常的方法是使用 map_err 将初始错误转换为您可以控制的更丰富的错误,例如

enum MyError {
    Parsing,
    Adding
}

get_num(1).map_err(|_| MyError::Parsing)
    .and_then(|v| add_one(v).map_err(|_| MyError::Adding)

遗憾的是,如您所见,这需要为 and_then 回调使用 lambda:and_then 必须 return 与输入的错误类型相同,因此这里它必须产生一个Result<_, MyError>,wjhich 不是 add_one 的 return 类型。

虽然在其他情况下我们可以使用 ? 进行一些恢复,但这里相同的原始错误 type 被拆分为两个不同的值。