Result 枚举

  1. enum Result<T, E> {
  2. Ok(T),
  3. Err(E),
  4. }
  • T: 操作成功情况下,Ok 变体里返回的数据的类型
  • E:操作失败情况下,Err 变体里返回的错误的类型

    处理 Result 的一种方式:match 表达式

  • 和 Option 枚举一样,Result 及其变体也是有 prelude 带入作用域 ```rust use std::fs::File;

fn main() { let f = File::open(“hello.txt”); let f = match f { Ok(file) => file, Err(error) => { panic!(“Error opening file {:?}”, error); } }; }

  1. 运行报错
  2. ```bash
  3. thread 'main' panicked at 'Error opening file Os
  4. { code: 2, kind: NotFound, message: "No such file or directory" }', src/main.rs:8:13

匹配不同的错误

  1. use std::fs::File;
  2. use std::io::ErrorKind;
  3. fn main() {
  4. let f = File::open("hello.txt");
  5. let f = match f {
  6. Ok(file) => file,
  7. Err(error) => match error.kind() {
  8. ErrorKind::NotFound => match File::create("hello.txt") {
  9. Ok(fc) => fc,
  10. Err(e) => panic!("Error creating file: {:?}", e),
  11. },
  12. other_error => panic!("Error opening file: {:?}", other_error),
  13. },
  14. };
  15. }
  • 上例中使用了很多 match
  • match 很有用,但是很原始
  • 闭包 (closure)。Result 有很多方法:
    • 它们接收闭包作为参数
    • 使用 match 实现
    • 使用这些方法会让代码更简洁 ```rust use std::fs::File; use std::io::ErrorKind;

fn main() { let f = File::open(“hello.txt”).unwrap_or_else(|error| { if error.kind() == ErrorKind::NotFound { File::create(“hello.txt”).unwrap_or_else(|error| { panic!(“Error creating file: {:?}”, error); }) } else { panic!(“Error opening file: {:?}”, error); } }); }

  1. <a name="Vfdv6"></a>
  2. ### unwrap
  3. - unwrap: match 表达式的一个快捷方法
  4. - 如果 Result 结果是 Ok,返回 Ok 里面的值
  5. - 如果 Result 结果是 Err,调用 panic! 宏
  6. ```rust
  7. use std::fs::File;
  8. use std::io::ErrorKind;
  9. fn main() {
  10. let f = File::open("hello.txt");
  11. let f = match f {
  12. Ok(file) => file,
  13. Err(error) => {
  14. panic!("Error opening file: {:?}", error)
  15. }
  16. };
  17. }

当尝试打开文件,如果成功打开 unwrap 会返回 Ok 里的值, 当函数 open 返回的是 Err 变体,unwrap 会调用 panic! 宏

  1. use std::fs::File;
  2. fn main() {
  3. let f = File::open("hello.txt").unwrap();
  4. }

运行结果

  1. thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os
  2. { code: 2, kind: NotFound, message: "No such file or directory" }'
  3. , src/main.rs:4:37

这个错误信息不可以自定义,这算是 unwrap 的一个缺点。针对这个缺点,Rust 提供了 expect

expect

  • expect:和 unwrap 类似,但可指定错误信息 ```rust use std::fs::File;

fn main() { let f = File::open(“hello.txt”).expect(“无法打开文件”); }

  1. 运行错误信息
  2. ```bash
  3. thread 'main' panicked at '无法打开文件: Os
  4. { code: 2, kind: NotFound, message: "No such file or directory" }'
  5. , src/main.rs:4:37

传播错误

  • 在函数处理错误
  • 将错误返回给调用者 ```rust use std::fs::File; use std::io; use std::io::Read;

fn read_username_from_file() -> Result { let f = File::open(“hello.txt”);

  1. let mut f = match f {
  2. Ok(file) => file,
  3. Err(e) => return Err(e),
  4. };
  5. let mut s = String::new();
  6. match f.read_to_string(&mut s) {
  7. Ok(_) => Ok(s),
  8. Err(e) => Err(e),
  9. }

}

fn main() { let result = read_username_from_file(); }

  1. <a name="gaW3t"></a>
  2. ### ? 运算符
  3. 传播错误的一种快捷方式
  4. ```rust
  5. use std::fs::File;
  6. use std::io;
  7. use std::io::Read;
  8. fn read_username_from_file() -> Result<String, io::Error> {
  9. let mut f = File::open("hello.txt")?;
  10. let mut s = String::new();
  11. f.read_to_string(&mut s)?;
  12. Ok(s)
  13. }
  14. fn main() {
  15. let result = read_username_from_file();
  16. }

File::open() 返回的是 Result 类型,加问号的作用就是

  1. let mut f = match f {
  2. Ok(file) => file,
  3. Err(e) => return Err(e),
  4. };
  • 如果 Result 是 Ok:Ok 中的值就是表达式的结果,然后继续执行程序
  • 如果 Result 是 Err:Err 就是整个函数的返回值,就像使用了 return

    ?与 from 函数

  • trait std::convert::From 上的 from 函数:

    • 用于错误之间的转换
  • 被 ?所接收的错误,会隐式的被 from 函数处理
  • 当 ?调用 from 函数时:
    • 它所接收的错误类型会被转化为当前函数返回类型所定义的错误类型
  • 用于:针对不同错误原因,返回同一种错误类型
    • 只要每个错误类型实现了转换为所返回的错误类型的 from 函数

      ?链式调用

      ```rust use std::fs::File; use std::io; use std::io::Read;

fn read_username_from_file() -> Result { let mut s = String::new(); File::open(“hello.txt”)?.read_to_string(&mut s)?; Ok(s) }

fn main() { let result = read_username_from_file(); }

  1. <a name="zOkNS"></a>
  2. ### ? 运算符只能用于返回 Result 的函数
  3. ```rust
  4. use std::fs::File;
  5. fn main() {
  6. let f = File::open("hello.txt")?;
  7. }

运行报错

  1. error[E0277]: the `?` operator can only be used in a function that
  2. returns `Result` or `Option` (or another type that implements `Try`)
  3. --> src/main.rs:13:13
  4. |
  5. 11 | / fn main() {
  6. 12 | | // let result = read_username_from_file();
  7. 13 | | let f = File::open("hello.txt")?;
  8. | | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
  9. 14 | | }
  10. | |_- this function should return `Result` or `Option` to accept `?`
  11. |
  12. = help: the trait `Try` is not implemented for `()`
  13. = note: required by `from_error`
  14. error: aborting due to previous error
  15. For more information about this error, try `rustc --explain E0277`.
  16. error: could not compile `string`
  17. To learn more, run the command again with --verbose.
  • 上面 main 函数的返回类型: ()
  • main 函数的返回类型也可以是:Result ```rust use std::error::Error; use std::fs::File;

fn main() -> Result<(), Box> { let f = File::open(“hello.txt”)?; Ok(()) } ```

  • Box 是 trait 对象
    • 简单理解:“任何可能的错误类型”