Rust错误处理库zenoh-result的使用:高效返回Result类型与自定义错误管理
⚠️ 警告 ⚠️
这个crate是用于Zenoh内部使用的。 不能保证API在任何版本(包括补丁更新)中保持不变。 强烈建议仅依赖zenoh和zenoh-ext crate并使用它们的公共API。
安装
在项目目录中运行以下Cargo命令:
cargo add zenoh-result
或者在Cargo.toml中添加以下行:
zenoh-result = "1.5.0"
zenoh-result使用示例
下面是一个使用zenoh-result进行错误处理和自定义错误管理的完整示例:
use zenoh_result::{Error as ZError, ZResult};
// 定义自定义错误类型
#[derive(Debug)]
enum MyError {
InvalidInput,
NetworkError(String),
InternalError,
}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MyError::InvalidInput => write!(f, "Invalid input provided"),
MyError::NetworkError(msg) => write!(f, "Network error: {}", msg),
MyError::InternalError => write!(f, "Internal server error"),
}
}
}
impl std::error::Error for MyError {}
// 将自定义错误转换为zenoh错误
impl From<MyError> for ZError {
fn from(err: MyError) -> Self {
ZError::new(err)
}
}
// 使用ZResult作为返回类型的函数
fn process_data(input: &str) -> ZResult<String> {
if input.is_empty() {
return Err(MyError::InvalidInput.into());
}
if input == "error" {
return Err(MyError::NetworkError("connection failed".to_string()).into());
}
Ok(input.to_uppercase())
}
fn main() {
match process_data("hello") {
Ok(result) => println!("Success: {}", result),
Err(e) => println!("Error: {}", e),
}
match process_data("") {
Ok(result) => println!("Success: {}", result),
Err(e) => println!("Error: {}", e), // 将输出: Error: Invalid input provided
}
match process_data("error") {
Ok(result) => println!("Success: {}", result),
Err(e) => println!("Error: {}", e), // 将输出: Error: Network error: connection failed
}
}
完整示例demo
// 引入zenoh-result库中的错误类型
use zenoh_result::{Error as ZError, ZResult};
// 定义更复杂的自定义错误类型
#[derive(Debug)]
enum AdvancedError {
ParseError(serde_json::Error),
DatabaseError(sqlx::Error),
CustomError { code: u32, message: String },
Timeout,
}
// 实现Display trait用于错误显示
impl std::fmt::Display for AdvancedError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
AdvancedError::ParseError(e) => write!(f, "JSON解析错误: {}", e),
AdvancedError::DatabaseError(e) => write!(f, "数据库错误: {}", e),
AdvancedError::CustomError { code, message } => write!(f, "自定义错误[{}]: {}", code, message),
AdvancedError::Timeout => write!(f, "操作超时"),
}
}
}
// 实现Error trait
impl std::error::Error for AdvancedError {}
// 实现从自定义错误到ZError的转换
impl From<AdvancedError> for ZError {
fn from(err: AdvancedError) -> Self {
ZError::new(err)
}
}
// 模拟数据库查询函数
fn query_database() -> ZResult<String> {
// 这里模拟一个数据库错误
Err(AdvancedError::DatabaseError(
sqlx::Error::Configuration("连接字符串无效".into())
).into())
}
// 模拟JSON解析函数
fn parse_json(input: &str) -> ZResult<serde_json::Value> {
// 这里模拟一个解析错误
serde_json::from_str(input).map_err(|e| AdvancedError::ParseError(e).into())
}
// 主函数演示各种错误处理
fn main() {
// 演示数据库错误处理
match query_database() {
Ok(data) => println!("数据库查询成功: {}", data),
Err(e) => println!("数据库操作失败: {}", e),
}
// 演示JSON解析错误处理
let invalid_json = "{ invalid: json }";
match parse_json(invalid_json) {
Ok(value) => println!("解析成功: {:?}", value),
Err(e) => println!("解析失败: {}", e),
}
// 演示自定义错误
let custom_error: ZResult<()> = Err(AdvancedError::CustomError {
code: 1001,
message: "这是一个自定义错误示例".to_string(),
}.into());
if let Err(e) = custom_error {
println!("捕获自定义错误: {}", e);
}
// 演示超时错误
let timeout_error: ZResult<()> = Err(AdvancedError::Timeout.into());
timeout_error.unwrap_or_else(|e| println!("发生超时: {}", e));
}
主要特点
- 使用
ZResult
作为返回类型,它是Result<T, ZError>
的别名 - 可以轻松地将自定义错误类型转换为
ZError
- 提供了统一的错误处理机制
- 错误信息可以方便地显示给用户
许可证
EPL-2.0 OR Apache-2.0
1 回复
Rust错误处理库zenoh-result的使用:高效返回Result类型与自定义错误管理
介绍
zenoh-result是Zenoh项目中的一个错误处理库,它提供了一套高效且灵活的错误处理机制,特别适合需要自定义错误类型和高效错误传播的场景。这个库的核心是ZResult
类型,它是对标准库Result
的扩展,提供了更丰富的功能和更好的性能。
主要特性
- 提供了
ZResult
类型作为Result
的替代 - 支持自定义错误类型的便捷创建
- 高效的错误传播机制
- 与标准库
Result
的良好互操作性
使用方法
基本使用
首先在Cargo.toml中添加依赖:
[dependencies]
zenoh-result = "0.2"
基本示例
use zenoh_result::{ZResult, zerror, bail};
// 定义一个简单的函数返回ZResult
fn divide(a: i32, b: i32) -> ZResult<i32> {
if b == 0 {
bail!("Division by zero");
}
Ok(a / b)
}
fn main() {
match divide(10, 2) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
match divide(10, 0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e), // 会打印"Division by zero"
}
}
自定义错误类型
use zenoh_result::{ZError, ZResult};
use std::fmt;
#[derive(Debug)]
enum MathError {
DivisionByZero,
NegativeNotAllowed,
}
impl fmt::Display for MathError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MathError::DivisionByZero => write!(f, "Division by zero is not allowed"),
MathError::NegativeNotAllowed => write?(f, "Negative numbers are not allowed"),
}
}
}
impl std::error::Error for MathError {}
fn safe_divide(a: i32, b: i32) -> ZResult<i32> {
if b == 0 {
return Err(ZError::new(MathError::DivisionByZero));
}
if a < 0 || b < 0 {
return Err(ZError::new(MathError::NegativeNotAllowed));
}
Ok(a / b)
}
fn main() {
match safe_divide(-10, 5) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e), // 会打印"Negative numbers are not allowed"
}
}
错误链
use zenoh_result::{ZResult, zerror, bail};
fn step1() -> ZResult<()> {
bail!("First error occurred");
}
fn step2() -> ZResult<()> {
step1().map_err(|e| zerror!("Step2 failed: {}", e))?;
Ok(())
}
fn main() {
if let Err(e) = step2() {
println!("Error chain: {}", e);
// 输出类似: Step2 failed: First error occurred
}
}
与标准Result互操作
use zenoh_result::ZResult;
use std::fs;
fn read_file(path: ?str) -> ZResult<String> {
// 使用?操作符自动将std::io::Error转换为ZError
let content = fs::read_to_string(path)?;
Ok(content)
}
fn main() {
match read_file("nonexistent.txt") {
Ok(content) => println!("File content: {}", content),
Err(e) => println!("Error reading file: {}", e),
}
}
高级用法
错误上下文
use zenoh_result::{ZResult, zerror};
fn process_data(data: &str) -> ZResult<()> {
if data.is_empty() {
return Err(zerror!("Empty data provided"));
}
// 处理数据...
Ok(())
}
fn main() {
let data = "";
if let Err(e) = process_data(data).map_err(|e| zerror!("Failed to process data: {}", e)) {
println!("Error: {}", e);
// 输出: Failed to process data: Empty data provided
}
}
性能优化
zenoh-result在设计上考虑了性能,特别是在错误路径上。当使用bail!
宏时,它比直接构造错误对象更高效:
use zenoh_result::{bail, ZResult};
fn efficient_check(value: i32) -> ZResult<i32> {
if value > 100 {
bail!("Value too large: {}", value);
}
Ok(value)
}
完整示例Demo
下面是一个结合了自定义错误类型、错误链和错误上下文的完整示例:
use zenoh_result::{ZResult, ZError, zerror, bail};
use std::fmt;
// 自定义错误类型
#[derive(Debug)]
enum AppError {
InvalidInput,
ProcessingFailed,
NetworkError(String),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AppError::InvalidInput => write!(f, "Invalid input provided"),
AppError::ProcessingFailed => write!(f, "Data processing failed"),
AppError::NetworkError(msg) => write!(f, "Network error: {}", msg),
}
}
}
impl std::error::Error for AppError {}
// 验证输入函数
fn validate_input(input: &str) -> ZResult<()> {
if input.is_empty() {
bail!(AppError::InvalidInput);
}
Ok(())
}
// 处理数据函数
fn process_data(input: &str) -> ZResult<String> {
validate_input(input)?;
if input == "error" {
bail!(AppError::ProcessingFailed);
}
// 模拟网络操作
if input == "network_error" {
bail!(ZError::new(AppError::NetworkError("Connection timeout".to_string())));
}
Ok(input.to_uppercase())
}
// 主函数
fn main() {
let test_cases = vec!["", "hello", "error", "network_error"];
for input in test_cases {
println!("Processing input: '{}'", input);
let result = process_data(input)
.map_err(|e| zerror!("Failed to process '{}': {}", input, e));
match result {
Ok(data) => println!("Success: {}", data),
Err(e) => println!("Error: {}", e),
}
println!("----------------------");
}
}
这个完整示例演示了:
- 自定义错误类型
AppError
的实现 - 使用
bail!
宏快速返回错误 - 错误链的构建(
validate_input
→process_data
) - 添加上下文信息(
zerror!
宏) - 多种错误情况的处理
输出示例:
Processing input: ''
Error: Failed to process '': Invalid input provided
----------------------
Processing input: 'hello'
Success: HELLO
----------------------
Processing input: 'error'
Error: Failed to process 'error': Data processing failed
----------------------
Processing input: 'network_error'
Error: Failed to process 'network_error': Network error: Connection timeout
----------------------
总结
zenoh-result提供了比标准库更丰富的错误处理功能,同时保持了高性能。它特别适合需要自定义错误类型、错误链和上下文信息的应用场景。通过ZResult
、zerror!
和bail!
等核心功能,开发者可以编写更清晰、更健壮的错误处理代码。