try! 的其他用法

    这是一个很简单且常见的操作,要是它能够省略的话将会相当方便。可惜的是,因为 and_then 不够灵活,所以它不能。但是,我们可改用 try!

    try! 在前面已经解释过,它可以充当 unwrapreturn Err(err),这说法只是很大程度上是对的。实际上它意味着 unwrap 或者 return Err(From::from(err))。由于 From::from 是一个不同类型间相互转换的工具,所以如果你使用 try!,当中的错误若能够转换成返回类型,这将会自动转换。

    1. use std::num::ParseIntError;
    2. use std::fmt;
    3. type Result<T> = std::result::Result<T, DoubleError>;
    4. #[derive(Debug)]
    5. enum DoubleError {
    6. EmptyVec,
    7. Parse(ParseIntError),
    8. }
    9. // 实现从 `ParseIntError` 到 `DoubleError` 的转换。如果一个 `ParseIntError`
    10. impl From<ParseIntError> for DoubleError {
    11. fn from(err: ParseIntError) -> DoubleError {
    12. DoubleError::Parse(err)
    13. }
    14. }
    15. impl fmt::Display for DoubleError {
    16. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    17. match *self {
    18. DoubleError::EmptyVec =>
    19. write!(f, "please use a vector with at least one element"),
    20. DoubleError::Parse(ref e) => e.fmt(f),
    21. }
    22. }
    23. }
    24. // 和前面的结构一样,但没有将全部的 `Results` 和 `Options` 链接在一起,
    25. // 我们使用 `try!` 立即得到内部的值。
    26. // (原文:// The same structure as before but rather than chain all `Results`
    27. // and `Options` along, we `try!` to get the inner value out immediately.)
    28. fn double_first(vec: Vec<&str>) -> Result<i32> {
    29. // 仍然转为 `Result`,通过规定怎样转为 `None`。
    30. // (原上:// Still convert to `Result` by stating how to convert `None`.)
    31. let first = try!(vec.first().ok_or(DoubleError::EmptyVec));
    32. let parsed = try!(first.parse::<i32>());
    33. Ok(2 * parsed)
    34. }
    35. fn print(result: Result<i32>) {
    36. match result {
    37. Ok(n) => println!("The first doubled is {}", n),
    38. Err(e) => println!("Error: {}", e),
    39. }
    40. }
    41. fn main() {
    42. let numbers = vec!["93", "18"];
    43. let empty = vec![];
    44. let strings = vec!["tofu", "93", "18"];
    45. print(double_first(numbers));
    46. print(double_first(empty));
    47. print(double_first(strings));
    48. }

    现在变得整洁多了。如果和原始的 panic 进行比较,可以看到它好像就是使用 try! 替换 unwrap,除了返回类型是 Result 类型这点不同,所以它们必须在顶层被解构出来。

    然而,不要指望这种错误处理经常取代 unwrap 的用法。这种错误处理会使代码行数扩大三倍,即便是很小的一段代码也不能称之为简单。

    很多库可能只是抛弃了实现 Display,然后在所需的基础上增加 From(原文:Many libraries might get away with only implementing Display and then adding From on an as needed basis.)。然而,越是正式的库最后越是需要面临实现更高级的错误处理的需求。

    From::from