Rust - 错误处理
在 Rust 中,错误可以分为两大类,如下表所示。
Sr.No | 名称 & 描述 | 用法 |
---|---|---|
1 | Recoverable 可处理的错误 | 结果枚举 |
2 | UnRecoverable 无法处理的错误 | panic 宏 |
可恢复错误是可以纠正的错误。 程序可以在遇到可恢复错误时重试失败的操作或指定备用操作过程。 可恢复的错误不会导致程序突然失败。 可恢复错误的一个示例是File Not Found(找不到文件)错误。
不可恢复的错误会导致程序突然失败。 如果发生不可恢复的错误,程序将无法恢复到正常状态。 它无法重试失败的操作或撤消错误。 不可恢复错误的一个示例是尝试访问超出数组末尾的位置。
与其他编程语言不同,Rust 没有例外。 对于可恢复的错误,它返回一个枚举 Result<T, E>;如果程序遇到不可恢复的错误,它会调用 panic 宏。 panic 宏导致程序突然退出。
Panic 宏和 Unrecoverable Errors
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]; //由于无法到达索引 10,因此引发 panic }
输出如下图 −
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.
程序可以引发紧急情况! 如果违反业务规则,则使用宏,如下例所示 −
fn main() { let no = 13; // 尝试奇数和偶数 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.
结果枚举和可恢复错误
枚举结果 - <T,E> 可用于处理可恢复的错误。 它有两个变体 − OK 和 Err。T 和 E 是泛型类型参数。T 表示 OK 变体中成功情况下将返回的值的类型,E 表示失败情况下将返回的错误类型 在 Err 变体中。
enum Result<T,E> { OK(T), Err(E) }
让我们通过一个例子来理解这一点 −
use std::fs::File; fn main() { let f = File::open("main.jpg"); // 该文件不存在 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 不存在 match f { Ok(f)=> { println!("file found {:?}",f); }, Err(e)=> { println!("file not found \n{:?}",e); // 处理错误 } } println!("end of main"); }
注意 − 尽管未找到文件,程序仍会打印 main 事件的 end。 这意味着程序已经妥善处理了错误。
输出
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 函数妥善处理错误,因此会打印 main 语句的 end 。
输出
Error msg is NOT_AN_EVEN end of main
unwrap() 和 expect()
标准库包含一些辅助方法,它们都枚举 − Result<T,E> 和 Option<T> 实施。 您可以使用它们来简化您确实不希望事情失败的错误情况。 如果方法成功,则使用"unwrap"函数提取实际结果。
Sr.No | 方法 | 函数 & 描述 |
---|---|---|
1 | unwrap | unwrap(self): T 期望 self 为 Ok/Some 并返回其中包含的值。 如果它是 Err 或 None,则会引发 panic 并显示错误内容。 |
2 | expect | expect(self, msg: &str): T 行为类似于 unwrap,只不过除了错误内容之外,它还会在 panic 之前输出一条自定义消息。 |
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"); // 文件不存在 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.