Resultmap

上一节的 multiply 函数的 panic 设计不是健壮的(robust)。一般地,我们希望把 错误返回给调用者,这样它可以决定回应错误的正确方式。

首先,我们需要了解需要处理的错误类型是什么。为了确定 Err 的类型,我们可以 用 parse() 来试验。Rust 已经为 i32 类型使用 FromStr trait 实现了 parse()。结果表明,这里的 Err 类型被指定为 ParseIntError

译注:原文没有具体讲如何确定 Err 的类型。由于目前用于获取类型的函数仍然是不 稳定的,我们可以用间接的方法。使用下面的代码:

  1. fn main () {
  2. let i: () = "t".parse::<i32>();
  3. }

由于不可能把 Result 类型赋给单元类型变量 i,编译器会提示我们:

  1. note: expected type `()`
  2. found type `std::result::Result<i32, std::num::ParseIntError>`

这样就知道了 parse<i32> 函数的返回类型详情。

在下面的例子中,使用简单的 match 语句导致了更加繁琐的代码。

  1. use std::num::ParseIntError;
  2. // 修改了上一节中的返回类型,现在使用模式匹配而不是 `unwrap()`。
  3. fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
  4. match first_number_str.parse::<i32>() {
  5. Ok(first_number) => {
  6. match second_number_str.parse::<i32>() {
  7. Ok(second_number) => {
  8. Ok(first_number * second_number)
  9. },
  10. Err(e) => Err(e),
  11. }
  12. },
  13. Err(e) => Err(e),
  14. }
  15. }
  16. fn print(result: Result<i32, ParseIntError>) {
  17. match result {
  18. Ok(n) => println!("n is {}", n),
  19. Err(e) => println!("Error: {}", e),
  20. }
  21. }
  22. fn main() {
  23. // 这种情形下仍然会给出正确的答案。
  24. let twenty = multiply("10", "2");
  25. print(twenty);
  26. // 这种情况下就会提供一条更有用的错误信息。
  27. let tt = multiply("t", "2");
  28. print(tt);
  29. }

幸运的是,Optionmapand_then、以及很多其他组合算子也为 Result 实现 了。官方文档的 Result 一节包含完整的方法列表。

  1. use std::num::ParseIntError;
  2. // 就像 `Option` 那样,我们可以使用 `map()` 之类的组合算子。
  3. // 除去写法外,这个函数与上面那个完全一致,它的作用是:
  4. // 如果值是合法的,计算其乘积,否则返回错误。
  5. fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
  6. first_number_str.parse::<i32>().and_then(|first_number| {
  7. second_number_str.parse::<i32>().map(|second_number| first_number * second_number)
  8. })
  9. }
  10. fn print(result: Result<i32, ParseIntError>) {
  11. match result {
  12. Ok(n) => println!("n is {}", n),
  13. Err(e) => println!("Error: {}", e),
  14. }
  15. }
  16. fn main() {
  17. // 这种情况下仍然会给出正确的答案。
  18. let twenty = multiply("10", "2");
  19. print(twenty);
  20. // 这种情况下就会提供一条更有用的错误信息。
  21. let tt = multiply("t", "2");
  22. print(tt);
  23. }