Rust 错误处理详解
可恢复的错误处理
Result 类型
Rust 使用 Result
枚举处理可恢复的错误:
enum Result<T, E> {
Ok(T), // 成功时返回的值
Err(E), // 错误时返回的错误信息
}
// 基本使用示例
fn read_username_from_file() -> Result<String, std::io::Error> {
let mut username = String::new();
// 打开文件可能失败
let mut file = std::fs::File::open("username.txt")?;
// 读取文件可能失败
file.read_to_string(&mut username)?;
Ok(username)
}
fn main() {
// 处理 Result
match read_username_from_file() {
Ok(username) => println!("用户名:{}", username),
Err(e) => println!("读取错误:{}", e),
}
}
panic! 宏
当程序遇到不可恢复的错误时,使用 panic!
:
fn main() {
// 立即终止程序
panic!("严重错误,程序无法继续");
// 数组越界会自动触发 panic
let v = vec![1, 2, 3];
v[99]; // 会触发 panic
}
? 运算符
简化错误处理的传播:
fn read_config() -> Result<String, std::io::Error> {
// ? 运算符会自动传播错误
let mut config = String::new();
std::fs::File::open("config.txt")?.read_to_string(&mut config)?;
Ok(config)
}
// 等价于
fn read_config_verbose() -> Result<String, std::io::Error> {
let mut config = String::new();
let mut file = match std::fs::File::open("config.txt") {
Ok(file) => file,
Err(e) => return Err(e),
};
match file.read_to_string(&mut config) {
Ok(_) => Ok(config),
Err(e) => Err(e),
}
}
自定义错误类型
#[derive(Debug)]
enum CustomError {
IoError(std::io::Error),
ParseError(std::num::ParseIntError),
ValidationError(String),
}
// 从其他错误类型转换
impl From<std::io::Error> for CustomError {
fn from(error: std::io::Error) -> Self {
CustomError::IoError(error)
}
}
fn process_data() -> Result<i32, CustomError> {
let content = std::fs::read_to_string("data.txt")?; // 自动转换 IoError
let number = content.trim().parse::<i32>()
.map_err(|e| CustomError::ParseError(e))?;
if number < 0 {
return Err(CustomError::ValidationError(
"数字不能为负".to_string()
));
}
Ok(number)
}
错误处理策略与库
anyhow 库:简化错误处理
use anyhow::{Result, Context};
fn complex_operation() -> Result<()> {
let file = std::fs::File::open("config.json")
.context("无法打开配置文件")?;
// 灵活的错误处理
let config: Config = serde_json::from_reader(file)
.context("解析配置文件失败")?;
Ok(())
}
thiserror 库:定义错误类型
use thiserror::Error;
#[derive(Error, Debug)]
enum DataStoreError {
#[error("数据读取错误")]
ReadError,
#[error("数据写入错误:{0}")]
WriteError(String),
#[error("连接错误:{source}")]
ConnectionError {
#[from]
source: std::io::Error,
},
}
fn operate_data_store() -> Result<(), DataStoreError> {
// 使用自定义错误
Err(DataStoreError::WriteError("磁盘已满".to_string()))
}
最佳实践
- 优先使用
Result
处理可恢复错误 - 谨慎使用
panic!
- 使用
?
运算符简化错误传播 - 为库创建专门的错误类型
- 提供有意义的错误上下文
错误处理模式
默认值模式
fn get_config(path: &str) -> Config {
std::fs::read_to_string(path)
.map(|content| parse_config(&content))
.unwrap_or_else(|_| Config::default())
}
日志记录模式
fn process_data() -> Result<()> {
match read_data() {
Ok(data) => process(data),
Err(e) => {
log::error!("数据处理失败:{}", e);
Err(e)
}
}
}
结语
Rust 的错误处理系统既安全又灵活。通过 Result
、?
运算符和第三方库,你可以编写健壮且富有表现力的错误处理代码。持续实践是掌握错误处理的关键。