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

主要特点

  1. 使用ZResult作为返回类型,它是Result<T, ZError>的别名
  2. 可以轻松地将自定义错误类型转换为ZError
  3. 提供了统一的错误处理机制
  4. 错误信息可以方便地显示给用户

许可证

EPL-2.0 OR Apache-2.0


1 回复

Rust错误处理库zenoh-result的使用:高效返回Result类型与自定义错误管理

介绍

zenoh-result是Zenoh项目中的一个错误处理库,它提供了一套高效且灵活的错误处理机制,特别适合需要自定义错误类型和高效错误传播的场景。这个库的核心是ZResult类型,它是对标准库Result的扩展,提供了更丰富的功能和更好的性能。

主要特性

  1. 提供了ZResult类型作为Result的替代
  2. 支持自定义错误类型的便捷创建
  3. 高效的错误传播机制
  4. 与标准库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!("----------------------");
    }
}

这个完整示例演示了:

  1. 自定义错误类型AppError的实现
  2. 使用bail!宏快速返回错误
  3. 错误链的构建(validate_inputprocess_data
  4. 添加上下文信息(zerror!宏)
  5. 多种错误情况的处理

输出示例:

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提供了比标准库更丰富的错误处理功能,同时保持了高性能。它特别适合需要自定义错误类型、错误链和上下文信息的应用场景。通过ZResultzerror!bail!等核心功能,开发者可以编写更清晰、更健壮的错误处理代码。

回到顶部