- Rust 教程
- Rust - 首页
- Rust - 简介
- Rust - 环境设置
- Rust - HelloWorld 示例
- Rust - 数据类型
- Rust - 变量
- Rust - 常量
- Rust - 字符串
- Rust - 运算符
- Rust - 决策
- Rust - 循环
- Rust - 函数
- Rust - 元组
- Rust - 数组
- Rust - 所有权
- Rust - 借用
- Rust - 切片
- Rust - 结构体
- Rust - 枚举
- Rust - 模块
- Rust - 集合
- Rust - 错误处理
- Rust - 泛型
- Rust - 输入输出
- Rust - 文件输入/输出
- Rust - 包管理器
- Rust - 迭代器和闭包
- Rust - 智能指针
- Rust - 并发
- Rust 有用资源
- Rust - 快速指南
- Rust - 有用资源
- Rust - 讨论
Rust - 错误处理
在 Rust 中,错误可以分为以下两大类,如下表所示。
序号 | 名称及描述 | 用法 |
---|---|---|
1 | 可恢复 可以处理的错误 | Result 枚举 |
2 | 不可恢复 无法处理的错误 | panic 宏 |
可恢复错误是可以纠正的错误。当程序遇到可恢复错误时,可以重试失败的操作或指定备用操作方案。可恢复错误不会导致程序突然失败。可恢复错误的一个示例是文件未找到错误。
不可恢复错误会导致程序突然失败。如果发生不可恢复错误,程序无法恢复到其正常状态。它无法重试失败的操作或撤消错误。不可恢复错误的一个示例是尝试访问数组末尾以外的位置。
与其他编程语言不同,Rust 没有异常。它为可恢复错误返回一个枚举Result<T, E>,而在程序遇到不可恢复错误时,它会调用panic宏。panic宏会导致程序突然退出。
Panic 宏和不可恢复错误
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 枚举和可恢复错误
枚举 Result – <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"); //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"); }
注意 - 即使文件未找到,程序也会打印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 函数优雅地处理了错误,因此打印了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,则它会引发 panic 并显示错误的内容。 |
2 | expect | expect(self, msg: &str): T 行为类似于 unwrap,除了在出现 panic 之前除了错误内容之外还会输出自定义消息。 |
unwrap()
unwrap()函数在操作成功时返回实际结果。如果操作失败,它会返回带有默认错误消息的 panic。此函数是 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()函数将出现 panic 并返回如下所示的默认错误消息
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()
程序可以在出现 panic 的情况下返回自定义错误消息。这在以下示例中显示:
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.