Error Handling
Unrecoverable Errors with panic!
Rust 的 可靠性:错误处理,大部分情况下:在编译时提示错误并处理
错误分类:
可恢复:例如文件未找到,可再次尝试
不可恢复:例如访问索引超出范围
默认情况下,当 panic 发生:
- 程序展开调用栈 (工作量大)
- Rust 沿着调用栈回走
- 清理每个遇到的函数中的数据
- 或 立即终止调用栈
- 不清理内存,直接停止程序,内存需要 OS 进行清理
panic!
宏
产生 panic 打印路径,行等信息
panic!("crash");
// thread 'main' panicked at src\main.rs:3:5:crash
panic!可能出现在我们写的代码中,我们所依赖的代码中
通过设置环境变量 RUST_BACKTRACE 可以得到回溯信息
Recoverable Errors with Result
Result 枚举
pub enum Result<T, E> {
Ok(T),
Err(E),
}
操作成功返回 Ok(T) 中的数据
操作失败返回 Err(E) 中的数据
例如打开一个文件, 返回 Result 类型
use std::fs::File;
fn main() {
let frs = File::open("some.txt");
let x = match frs {
Ok(file) => file,
Err(error) => {
panic!("Not find file {:#?}", error);
}
};
}
输出信息
thread 'main' panicked at src\main.rs:9:13:
Not find file Os {
code: 2,
kind: NotFound,
message: "系统找不到指定的文件。",
}
传播错误,将错误返回,让调用者决定如何处理
例如
fn read_username_from_file(path: &str) -> Result<String, io::Error> {
let frs = File::open(path);
let mut f = match frs {
Ok(file) => file,
Err(err) => return Err(err),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
?
运算符 传播错误的一种快捷方式
例如,与上面功能一样
fn read_username_from_file(path: &str) -> Result<String, io::Error> {
let mut f = File::open(path)?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
// let mut f = File::open(path)?;
// 等于
// let mut f = match frs {
// Ok(file) => file,
// Err(err) => return Err(err),
// };
即 ?
作用于 Result ,成功即 Ok(T) 中的 T, 失败即 return Err
链式调用的方式
fn read_username_from_file(path: &str) -> Result<String, io::Error> {
let mut s = String::new();
File::open(path)?.read_to_string(&mut s)?;
Ok(s)
}
To panic! or Not to panic!
示例、 代码原型和测试都非常适合 panic
当我们比编译器知道更多的情况,当你有一些其他的逻辑来确保 Result 会是 Ok 值时,调用 unwrap 或者 expect 也是合适的
错误处理指导原则:在当有可能会导致有害状态的情况下建议使用 panic!
当错误预期会出现时,返回 Result 仍要比调用 panic! 更为合适