Rust错误处理库boxed_error的使用,BoxedError提供便捷的错误类型封装与统一处理方案

Rust错误处理库boxed_error的使用

boxed_error是一个实验性的库,提供了帮助方法来简化错误装箱处理。它为Boxed错误类型提供了便捷的封装与统一处理方案。

使用前示例

use thiserror::Error;

#[derive(Error, Debug)]
#[error(transparent)]
pub struct DenoResolveError(pub Box<DenoResolveErrorKind>);

impl DenoResolveError {
  pub fn as_kind(&self) -> &DenoResolveErrorKind {
    &self.0
  }

  pub fn into_kind(self) -> DenoResolveErrorKind {
    *self.0
  }
}

impl<E> From<E> for DenoResolveError
where
  DenoResolveErrorKind: From<E>,
{
  fn from(err: E) -> Self {
    DenoResolveError(Box::new(DenoResolveErrorKind::from(err)))
  }
}

#[derive(Debug, Error)]
pub enum DenoResolveErrorKind {
  #[error("Importing ...")]
  InvalidVendorFolderImport,
  #[error(transparent)]
  MappedResolution(#[from] MappedResolutionError),
  // ...
}

impl DenoResolveErrorKind {
  pub fn into_box(self) -> DenoResolveError {
    DenoResolveError(Box::new(self))
  }
}

使用后示例

use boxed_error::Boxed;
use thiserror::Error;

#[derive(Debug, Boxed)]
pub enum DenoResolveError(pub Box<DenoResolveErrorKind>);

#[derive(Debug, Error)]
pub enum DenoResolveErrorKind {
  #[error("Importing ...")]
  InvalidVendorFolderImport,
  #[error(transparent)]
  MappedResolution(#[from] MappedResolutionError),
  // ...
}

完整示例

use boxed_error::Boxed;
use thiserror::Error;

// 定义Boxed错误类型
#[derive(Debug, Boxed)]
pub struct MyError(pub Box<MyErrorKind>);

// 定义具体的错误种类
#[derive(Debug, Error)]
pub enum MyErrorKind {
    #[error("IO error occurred")]
    Io(#[from] std::io::Error),
    #[error("Parse error occurred")]
    Parse(#[from] std::num::ParseIntError),
    #[error("Custom error: {0}")]
    Custom(String),
}

// 使用示例
fn might_fail() -> Result<(), MyError> {
    // 自动装箱转换
    let _: MyError = std::io::Error::new(std::io::ErrorKind::Other, "oh no!").into();
    Ok(())
}

fn main() {
    if let Err(e) = might_fail() {
        // 通过Boxed derive自动获得的方法
        let kind = e.as_kind();
        println!("Error kind: {:?}", kind);
        
        let owned_kind = e.into_kind();
        println!("Owned error kind: {:?}", owned_kind);
    }
}

主要功能

  1. 通过#[derive(Boxed)]自动生成以下方法:

    • as_kind() - 获取对内部错误类型的引用
    • into_kind() - 获取拥有所有权的内部错误类型
    • From实现 - 自动装箱转换
  2. thiserror无缝集成,简化错误类型定义

  3. 减少样板代码,让错误处理更简洁

安装方式:

[dependencies]
boxed_error = "0.2.3"

1 回复

Rust错误处理库boxed_error的使用

BoxedError是一个Rust错误处理工具库,它提供了便捷的错误类型封装与统一处理方案,简化了Rust中的错误处理流程。

核心特性

  • 将任意错误类型自动装箱为Box<dyn std::error::Error>
  • 提供统一的错误处理接口
  • 支持错误链追踪
  • 简化错误类型之间的转换

基本使用方法

安装

在Cargo.toml中添加依赖:

[dependencies]
boxed_error = "0.1"

基本示例

use boxed_error::BoxedError;
use std::error::Error;
use std::fmt;

#[derive(Debug)]
struct MyCustomError {
    details: String,
}

impl fmt::Display for MyCustomError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for MyCustomError {}

fn might_fail() -> Result<(), BoxedError> {
    // 将自定义错误转换为BoxedError
    Err(MyCustomError { details: "Something went wrong".into() }.into())
}

fn main() {
    match might_fail() {
        Ok(_) => println!("Success!"),
        Err(e) => println!("Error occurred: {}", e),
    }
}

高级用法

错误链

use boxed_error::BoxedError;

fn step_one() -> Result<(), BoxedError> {
    Err("Step one failed".into())
}

fn step_two() -> Result<(), BoxedError> {
    step_one().map_err(|e| e.context("While executing step two"))?;
    Ok(())
}

fn main() {
    if let Err(e) = step_two() {
        println!("Error chain:");
        for cause in e.chain() {
            println!("- {}", cause);
        }
    }
}

错误转换

use boxed_error::BoxedError;

fn parse_number(s: &str) -> Result<i32, BoxedError> {
    s.parse().map_err(|e: std::num::ParseIntError| {
        BoxedError::new(e).context(format!("Failed to parse '{}' as integer", s))
    })
}

fn main() {
    match parse_number("not a number") {
        Ok(n) => println!("Parsed number: {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

与anyhow/thiserror互操作

use boxed_error::BoxedError;
use thiserror::Error;

#[derive(Error, Debug)]
#[error("Database error: {0}")]
struct DatabaseError(String);

fn db_operation() -> Result<(), BoxedError> {
    // 模拟数据库错误
    Err(DatabaseError("Connection failed".to_string()).into())
}

fn main() {
    if let Err(e) = db_operation() {
        if let Some(db_err) = e.downcast_ref::<DatabaseError>() {
            println!("Specific database error: {}", db_err);
        } else {
            println!("Other error: {}", e);
        }
    }
}

最佳实践

  1. 在应用边界将具体错误转换为BoxedError
  2. 使用context()方法添加错误上下文信息
  3. 利用downcast系列方法处理特定错误类型
  4. 使用chain()方法遍历错误链进行详细日志记录

BoxedError特别适合在需要统一处理多种错误类型的场景,如应用程序的顶层错误处理或库的公共接口。

完整示例

下面是一个结合上述所有特性的完整示例:

use boxed_error::BoxedError;
use std::error::Error;
use std::fmt;
use thiserror::Error;

// 自定义错误类型1
#[derive(Debug)]
struct CustomError1 {
    message: String,
}

impl fmt::Display for CustomError1 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CustomError1: {}", self.message)
    }
}

impl Error for CustomError1 {}

// 自定义错误类型2 (使用thiserror)
#[derive(Error, Debug)]
#[error("CustomError2: {0}")]
struct CustomError2(String);

// 模拟数据库操作
fn db_query() -> Result<(), CustomError1> {
    Err(CustomError1 {
        message: "Database query failed".to_string(),
    })
}

// 模拟业务逻辑
fn business_logic() -> Result<(), BoxedError> {
    // 转换错误类型
    db_query().map_err(|e| BoxedError::new(e).context("In business_logic"))?;
    
    // 模拟其他错误
    "123a".parse::<i32>()
        .map_err(|e| BoxedError::new(e).context("Parsing integer failed"))?;
    
    Ok(())
}

// 顶层应用逻辑
fn application() -> Result<(), BoxedError> {
    business_logic().map_err(|e| e.context("In application"))?;
    
    // 模拟thiserror错误
    Err(CustomError2("Something went wrong".to_string()).into())
}

fn main() {
    match application() {
        Ok(_) => println!("Application succeeded"),
        Err(e) => {
            println!("Application failed with error: {}", e);
            println!("\nError chain:");
            
            // 打印错误链
            for (i, cause) in e.chain().enumerate() {
                println!("{}: {}", i + 1, cause);
            }
            
            // 尝试downcast特定错误类型
            if let Some(custom_err) = e.downcast_ref::<CustomError1>() {
                println!("\nDetected CustomError1: {}", custom_err);
            }
            
            if let Some(custom_err) = e.downcast_ref::<CustomError2>() {
                println!("\nDetected CustomError2: {}", custom_err);
            }
        }
    }
}

这个完整示例演示了:

  1. 自定义错误类型的定义
  2. 错误类型转换
  3. 错误上下文添加
  4. 错误链追踪
  5. 特定错误类型的downcast处理
  6. 与thiserror的互操作
回到顶部