八、错误处理
在 Rust 中,存在两种错误:
- 不可恢复的错误,这类错误场景被称为
panic - 可恢复的错误,这类错误通常由
Result<T, E>提供
1. 不可恢复的错误
-
在 Rust 中,
panic即为不可恢复的错误 -
遇到
panic时的退出方式panic = 'abort'- 直接退出,不展开清理内存,让操作系统来清理
- 优点:项目的最终二进制文件更小
panic = 'unwinding'- 展开并回溯栈,Rust 程序自己清理内存
-
使用示例
// 手动 panic 时,使用 panic! 宏即可 // 来自官方教程的一个示例 fn main() { panic!("crash and burn"); }
2. 可恢复的错误
-
可恢复的错误,通常是指可以在程序中被捕获的错误,这个错误通常由
Result<T, E>来提供 -
对于一个错误,可通过
?符来向外传递这个错误// 来自官方教程的一个示例 use std::io; use std::io::Read; use std::fs::File; fn read_username_from_file() -> Result<String, io::Error> { let mut f = File::open("hello.txt")?; // 如果文件打开失败,会将这个错误向外传播 let mut s = String::new(); f.read_to_string(&mut s)?; // 如果文件读取失败,会将这个错误向外传播 Ok(s) } // 再简化一点 fn read_username_from_file2() -> Result<String, io::Error> { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) } // 再再简化一点 fn read_username_from_file3() -> Result<String, io::Error> { fs::read_to_string("hello.txt") } -
?运算符可被用于返回值类型为Result的函数- 注意:只能在返回
Result或者其它实现了std::ops::Try类型的函数中使用?运算符- 解决方式1:将函数返回值类型修改为
Result(前提是没有其它限制阻止这样做) - 解决方式2: 通过合适的方法使用
match或Result来处理Result<T, E>
- 解决方式1:将函数返回值类型修改为
- 注意:只能在返回
-
之前我们一直在写
main,且没有给它指定返回值类型,实际上main函数允许以下两类返回值类型:(),即我们通常默认的写法Result<T, E>,即可以返回一个可以携带错误的Result
3. 关于错误的处理
-
如果代码
panic了,那么应用程序是不可能自动恢复的 -
适合
panic的场景- 示例、代码原型和测试用例中
- 当 developer 比编译器知道得更多时
- 某些处理结果有可能会导致有害状态时
-
适合返回
Result<T, E>的场景- 某些错误预期会出现时