赞
踩
可恢复错误:Result<T,E>。文件查找不存在,可以重试。
不可恢复错误:panic!()宏。访问数组越界,会发生panic
处理方式:
栈展开:Rust会沿着调用栈的反向顺序遍历所有调用函数,并依次清理这些函数中的数据。
立即终止:直接结束程序且不进行任何清理工作,程序所使用过的内存只能由操作系统来进行回收。
Cargo.toml文件中添加配置:
- [profile.release]
- panic = 'abort'
在最终生成包里会采用立即终止程序
获取回溯信息:
回溯信息可能包含Rust核心库、标准库和第三方库
RUST_BACKTRACE=1 cargo run
- num Result<T, E> {
- Ok(T),
- Err(E),
- }
T代表了Ok变体中包含的值类型;E则代表了Err变体中包含的错误类型
Result枚举及其变体已经通过预导入模块被自动地引入当前作用域中
可以根据不同的错误原因,做出不同的处理:
- use std::fs::File;
- use std::io::ErrorKind;
-
- let f = File::open("hello.txt");
-
- let f = match f {
- Ok(file) => file,
- Err(error) => match error.kind() { // error.kind() 返回的是枚举类型;该枚举类型需要引入标准库的ErrorKind
- ErrorKind::NotFound => match File::create("hello.txt") {
- Ok(fc) => fc,
- Err(e) => panic!("Tried to create file but there was a problem: {:?}", e),
- },
- other_error => panic!("There was a problem opening the file: {:?}", other_error), // 这里使用了other_error,表示不再穷举,对剩余的情况的统一处理
- },
- };
File::open返回的Err变体中的错误值类型,是定义在某个标准库中的结构体类型:io::Error。这个结构体拥有一个被称作kind的方法,调用它来获得io::ErrorKind值。
ErrorKind枚举:
- enum ErrorKind {
- NotFound,
- PermissionDenied,
- DiskFull,
- }
利用闭包简化match嵌套:
- let f = File::open("hello.txt").map_err(|error| { // 这里调用map_err()函数,里面是闭包函数
- if error.kind() == ErrorKind::NotFound {
- File::create("hello.txt").unwrap_or_else(|error| { // 这里调用unwrap_or_else()函数,里面是闭包
- panic!("Tried to create file but there was a problem: {:?}", error);
- })
- } else {
- panic!("There was a problem opening the file: {:?}", error);
- }
- });
这里使用了两个函数map_err()和unwrap_or_else():
map_err():
map_err 方法用于将错误类型从一个类型转换为另一个类型。它接收一个闭包(closure),该闭包将原始错误类型转换为新的错误类型。map_err 通常用于在错误处理链中将错误类型统一化,以便更方便地处理错误。
该代码中error.kind() 将io::Error转换成io::ErrorKind, 然后进行比较。
- use std::fs::File;
- use std::io::Error;
-
- let file = File::open("non_existent_file.txt").map_err(|err| {
- Error::new(err.kind(), "文件不存在")
- });
使用 map_err 将 io::Error 转换为自定义的 Error 类型。
unwrap_or_else():
unwrap_or_else 方法用于处理 Option 或 Result 类型的值。如果值是 Some 或 Ok,则返回其中的值;否则,执行提供的闭包,并返回闭包的返回值。
- let value = Some(42);
- let result = value.unwrap_or_else(|| 0); // 成功返回42,失败返回0
- println!("result: {}", result); // 输出:result: 42
-
- let none_value: Option<i32> = None;
- let result = none_value.unwrap_or_else(|| 0);
- println!("result: {}", result); // 输出:result: 0
快速触发panic的两个方法:(中断程序继续运行)
unwrap(): 当Result的返回值是Ok变体时,unwrap就会返回Ok内部的值。而当Result的返回值是Err变体时,unwrap则会替我们调用panic! 宏
expect(): 基于unwrap函数,expect("xxx") 可以传入参数,表明错误的具体原因
- fn read_username_from_file() -> Result<String, io::Error> {
- let f = File::open("hello.txt");
- let mut f = match f {
- Ok(file) => file,
- Err(e) => return Err(e), // 通过return返回Err(e) ,将错误返回给调用者
- };
- let mut s = String::new();
- match f.read_to_string(&mut s) {
- Ok(_) => Ok(s),
- Err(e) => Err(e), // 返回Err,返回给调用者。由于这里是函数的最后一个表达式,所以我们不再需要显式地添加return。
- }
- }
传播错误的模式在Rust编程中非常常见,所以Rust专门提供了一个问号运算符(?)来简化它的语法。
将?放置于Result值。假如这个Result的值是Ok,那么包含在Ok中的值就会作为这个表达式的结果返回并继续执行程序。假如值是Err,那么这个值就会作为整个程序的结果返回,如同使用了return一样将错误传播给调用者。
使用了?运算符的函数必须返回Result、Option或任何实现了std::ops::Try的类型
- fn read_username_from_file() -> Result<String, io::Error> { // 返回类型是Result<String,io::Error>
- let mut s = String::new();
-
- File::open("hello.txt")?.read_to_string(&mut s)?; //这里是加分号
-
- Ok(s)
- }
std::io::Error: 表示I/O错误的类型。它包含一个ErrorKind和一个可选的错误消息,用于表示I/O操作过程中的错误,例如文件I/O,网络I/O或其他类型的I/O。
std::io::ErrorKind: 它是一个枚举,表示I/O错误的类型。它的枚举变体有NotFound,PermissionDenied,ConnectionRefused和其他类型。ErrorKind用于对I/O错误的类型进行分类,使其更容易处理和响应不同类型的错误。
std::error::Error: 表示一个泛型的错误类型的trait。它提供一种将错误类型转换为字符串的方法,从而可以向用户显示错误消息。Error是io::Error的超trait。意味着,上线了io::Error也实现了Error。
- use std::error::Error;
-
- fn main() -> Result<(), Box<dyn Error>> { // 允许将错误转换成字符串显示给用户
- let file = File::open("non_existent_file.txt")?;
- Ok(())
- }
代码一旦发生panic,就再也没有恢复的可能了.
返回一个Result值时,你就将这种选择权交给了调用者
通过人工检查确保代码永远不会出现Err变体,那就使用unwrap。unwrap内部是调用panic!()宏。
某个错误可能会导致代码处于损坏状态时,使用panic来处理错误。损坏状态意味着设计中的一些假设、保证、约定或不可变性出现了被打破的情形。比如,当某些非法的值、自相矛盾的值或不存在的值被传入代码中
假如错误是可预期的,那么就应该返回一个Result而不是调用panic!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。