这是Rust基础系列的第10篇文章(终结篇)。Rust将错误分为两大类:使用 panic! 处理的不可恢复错误,以及使用 Result<T, E> 处理的可恢复错误。
使用 panic! 处理不可恢复错误#
当程序遇到无法继续运行的致命情况(如数组越界访问)时,Rust会执行 panic! 宏。这会打印失败信息、展开栈(unwind stack)并退出进程:
fn main() {
// panic!("崩溃并终止");
let v = vec![1, 2, 3];
// v[99]; // 自动触发 panic
}rust仅在程序遇到无法自行修复的非法状态时使用 panic!。
使用 Result 处理可恢复错误#
对于可能在预料之中失败的操作(如打开文件或解析整数),函数会返回 Result<T, E>:
enum Result<T, E> {
Ok(T),
Err(E),
}rust你可以使用 match 来检查 Result:
use std::fs::File;
fn main() {
let greeting_file_result = File::open("hello.txt");
let _greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => panic!("打开文件时遇到问题:{error:?}"),
};
}rust快捷方式:unwrap 与 expect#
Result 提供了提取 T 或在遇到 Err 时触发 panic 的便捷方法:
let file = File::open("hello.txt").unwrap();
let file = File::open("hello.txt").expect("hello.txt 应该存在于当前目录中");rust在生产环境中推荐优先使用 expect 而不是 unwrap,因为它能在崩溃日志中提供有价值的上下文。
使用 ? 运算符传递错误#
编写函数时,你常常希望将错误向上传递给调用者,而不是在当前函数中立即处理。? 运算符提供了优雅且简洁的错误传递语法:
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username = String::new();
File::open("hello.txt")?.read_to_string(&mut username)?;
Ok(username)
}
fn main() -> Result<(), io::Error> {
let username = read_username_from_file()?;
println!("用户名:{username}");
Ok(())
}rust如果使用 ? 评估的操作返回了 Err,该 Err 会立刻作为当前函数的返回值被返回。
总结#
Rust的错误处理非常明确:panic! 应对不可恢复的致命错误,Result<T, E> 管理可恢复错误,而 ? 运算符实现了人体工程学般的优雅传递。至此,全套10篇Rust基础系列教程全部圆满完成!