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);
}
}
主要功能
-
通过
#[derive(Boxed)]
自动生成以下方法:as_kind()
- 获取对内部错误类型的引用into_kind()
- 获取拥有所有权的内部错误类型From
实现 - 自动装箱转换
-
与
thiserror
无缝集成,简化错误类型定义 -
减少样板代码,让错误处理更简洁
安装方式:
[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);
}
}
}
最佳实践
- 在应用边界将具体错误转换为
BoxedError
- 使用
context()
方法添加错误上下文信息 - 利用
downcast
系列方法处理特定错误类型 - 使用
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);
}
}
}
}
这个完整示例演示了:
- 自定义错误类型的定义
- 错误类型转换
- 错误上下文添加
- 错误链追踪
- 特定错误类型的downcast处理
- 与thiserror的互操作