Rust - 错误处理

  • 简述

    在 Rust 中,错误可以分为两大类,如下表所示。
    序号 名称 & 描述 用法
    1
    Recoverable
    可处理的错误
    Result enum
    2
    UnRecoverable
    无法处理的错误
    panic macro
    可恢复错误是可以纠正的错误。当程序遇到可恢复的错误时,它可以重试失败的操作或指定替代的操作过程。可恢复的错误不会导致程序突然失败。可恢复错误的一个示例是找不到文件错误。
    不可恢复的错误会导致程序突然失败。如果发生不可恢复的错误,程序将无法恢复到正常状态。它无法重试失败的操作或撤消错误。不可恢复错误的一个示例是尝试访问超出数组末尾的位置。
    与其他编程语言不同,Rust 没有异常。它为可恢复的错误返回一个枚举Result<T, E>,同时它调用panic宏,如果程序遇到不可恢复的错误。在恐慌宏导致程序突然退出了。
  • Panic 宏和 Unrecoverable 错误

    panic! 宏允许程序立即终止并向程序调用者提供反馈。当程序达到不可恢复状态时应该使用它。
    
    fn main() {
       panic!("Hello");
       println!("End of main"); //unreachable statement
    }
    
    在上面的例子中,程序在遇到panic!时会立即终止。

    输出

    
    thread 'main' panicked at 'Hello', main.rs:3
    

    说明:panic!

    
    fn main() {
       let a = [10,20,30];
       a[10]; //invokes a panic since index 10 cannot be reached
    }
    
    输出如下所示 -
    
    warning: this expression will panic at run-time
    --> main.rs:4:4
      |
    4 | a[10];
      | ^^^^^ index out of bounds: the len is 3 but the index is 10
    $main
    thread 'main' panicked at 'index out of bounds: the len 
    is 3 but the index is 10', main.rs:4
    note: Run with `RUST_BACKTRACE=1` for a backtrace.
    
    一个程序可以调用 panic! 宏,如果违反业务规则,如下例所示 -
    
    fn main() {
       let no = 13; 
       //try with odd and even
       if no%2 == 0 {
          println!("Thank you , number is even");
       } else {
          panic!("NOT_AN_EVEN"); 
       }
       println!("End of main");
    }
    
    如果分配给变量的值为奇数,则上面的示例将返回错误。

    输出

    
    thread 'main' panicked at 'NOT_AN_EVEN', main.rs:9
    note: Run with `RUST_BACKTRACE=1` for a backtrace.
    
  • Result 枚举和 Recoverable 错误

    Result - <T,E> 可用于处理可恢复的错误。它有两种变体 -OKErr. TE 是泛型类型参数。 T 表示将在 OK 变体中的成功案例中返回的值的类型,以及 E 表示将在 Err 变体中的失败情况下返回的错误类型。
    
    enum Result<T,E> {
       OK(T),
       Err(E)
    }
    
    让我们通过一个例子来理解这一点 -
    
    use std::fs::File;
    fn main() {
       let f = File::open("main.jpg"); 
       //this file does not exist
       println!("{:?}",f);
    }
    
    如果文件已经存在,程序返回OK(File),如果找不到文件,则返回Err(Error)
    
    Err(Error { repr: Os { code: 2, message: "No such file or directory" } })
    
    现在让我们看看如何处理 Err 变体。
    以下示例处理使用打开文件时返回的错误 match 陈述
    
    use std::fs::File;
    fn main() {
       let f = File::open("main.jpg");   // main.jpg doesn't exist
       match f {
          Ok(f)=> {
             println!("file found {:?}",f);
          },
          Err(e)=> {
             println!("file not found \n{:?}",e);   //handled error
          }
       }
       println!("end of main");
    }
    
    注意-该程序打印"end of main",虽然未找到文件。这意味着程序已经优雅地处理了错误。

    输出

    
    file not found
    Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }
    end of main
    

    说明

    如果数字不是偶数,is_even函数将返回错误。main() 函数处理这个错误。
    
    fn main(){
       let result = is_even(13);
       match result {
          Ok(d)=>{
             println!("no is even {}",d);
          },
          Err(msg)=>{
             println!("Error msg is {}",msg);
          }
       }
       println!("end of main");
    }
    fn is_even(no:i32)->Result<bool,String> {
       if no%2==0 {
          return Ok(true);
       } else {
          return Err("NOT_AN_EVEN".to_string());
       }
    }
    
    注意-由于main函数处理错误,"end of main"被打印。

    输出

    
    Error msg is NOT_AN_EVEN
    end of main
    
  • unwrap() 和 expect()

    标准库包含两个枚举 - Result <T,E>和 Option <T>实现的辅助方法。您可以使用它们来简化您真的不希望事情失败的错误情况。在方法成功的情况下,“unwrap”函数用于提取实际结果。
    序号 方法 签名 & 描述
    1 unwrap
    unwrap(self): T
    期望 self 为 Ok/Some 并返回其中包含的值。如果是Err 或者 None 相反,它会引发恐慌并显示错误的内容。
    2 expect
    expect(self, msg: &str): T
    行为类似于解包,除了它在恐慌之前除了错误的内容之外输出自定义消息。
  • unwrap()

    unwrap() 函数返回操作成功的实际结果。如果操作失败,它将返回带有默认错误消息的恐慌。此函数是 match 语句的简写。这在下面的示例中显示 -
    
    fn main(){
       let result = is_even(10).unwrap();
       println!("result is {}",result);
       println!("end of main");
    }
    fn is_even(no:i32)->Result<bool,String> {
       if no%2==0 {
          return Ok(true);
       } else {
          return Err("NOT_AN_EVEN".to_string());
       }
    }
    result is true
    end of main
    
    修改上面的代码,传递一个奇数给 is_even() 功能。
    unwrap()函数将报出错误和如下所示返回缺省错误消息
    
    thread 'main' panicked at 'called `Result::unwrap()` on 
    an `Err` value: "NOT_AN_EVEN"', libcore\result.rs:945:5
    note: Run with `RUST_BACKTRACE=1` for a backtrace
    
  • expect()

    程序可以在发生紧急情况时返回自定义错误消息。这在以下示例中显示 -
    
    use std::fs::File;
    fn main(){
       let f = File::open("pqr.txt").expect("File not able to open");
       //file does not exist
       println!("end of main");
    }
    
    函数expect() 类似于unwrap()。唯一的区别是可以使用expect 显示自定义错误消息。

    输出

    
    thread 'main' panicked at 'File not able to open: Error { repr: Os 
    { code: 2, message: "No such file or directory" } }', src/libcore/result.rs:860
    note: Run with `RUST_BACKTRACE=1` for a backtrace.