Rust 错误处理详解

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()))
}

最佳实践

  1. 优先使用 Result 处理可恢复错误
  2. 谨慎使用 panic!
  3. 使用 ? 运算符简化错误传播
  4. 为库创建专门的错误类型
  5. 提供有意义的错误上下文

错误处理模式

默认值模式

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? 运算符和第三方库,你可以编写健壮且富有表现力的错误处理代码。持续实践是掌握错误处理的关键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老大白菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值