Rust代码示例——18.5.2.定义一个错误类型

有时通过将所有不同类型的错误标志为单一的错误类型来简化代码。下面我们将展示如何自定义一个错误类型。

  1. Rust允许用户自定义错误类型。通常一个好的错误类型有一些特征:
  2. 使用相同的类型代表不同的错误
  3. 向用户展示友好的错误信息
  4. 容易和其他错误类型进行比较:
    • 好的:Err(EmptyVec)
    • 坏的:Err("Please use a vector with at least one element".to_owned())
  5. 和其他错误类型组合容易
use std::fmt;


type Result<T> = std::result::Result<T, DoubleError>;


// Define our error types. These may be customized for our error handling cases.

// Now we will be able to write our own errors, defer to an underlying error

// implementation, or do something in between.

#[derive(Debug, Clone)]

struct DoubleError;


// Generation of an error is completely separate from how it is displayed.

// There's no need to be concerned about cluttering complex logic with the display style.

//

// Note that we don't store any extra info about the errors. This means we can't state

// which string failed to parse without modifying our types to carry that information.

impl fmt::Display for DoubleError {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        write!(f, "invalid first item to double")

    }

}


fn double_first(vec: Vec<&str>) -> Result<i32> {

    vec.first()

        // Change the error to our new type.

        .ok_or(DoubleError)

        .and_then(|s| {

            s.parse::<i32>()

                // Update to the new error type here also.

                .map_err(|_| DoubleError)

                .map(|i| 2 * i)

        })

}


fn print(result: Result<i32>) {

    match result {

        Ok(n) => println!("The first doubled is {}", n),

        Err(e) => println!("Error: {}", e),

    }

}


fn main() {

    let numbers = vec!["42", "93", "18"];

    let empty = vec![];

    let strings = vec!["tofu", "93", "18"];


    print(double_first(numbers));

    print(double_first(empty));

    print(double_first(strings));

}
内容解析
为什么要自定义错误类型

在复杂的程序中,函数可能遇到多种不同的错误。使用自定义错误类型可以:

  1. 统一错误处理:将多种不同的错误类型封装成一种类型,简化函数签名和错误处理逻辑。
  2. 提供更好的信息:可以在错误类型中携带具体的错误信息(如错误值,位置等),而不仅仅是字符串。
  3. 提升可读性和可维护性:有明确类型的错误比字符串错误更容易比较、匹配和调试。
  4. 更好的组合性:自定义错误类型可以更容易地与其他错误类型交互和转换。
什么事好的错误类型

良好错误类型的特征:

  1. 统一表示:用同一类型表示不同错误
  2. 友好信息:为用户提供清晰的错误消息
  3. 易于比较:Err(EmptyVec)比Err(“message”.to_owned())更好
  4. 携带信息:能够保存错误相关的上下文信息
  5. 组合性好:能与其他错误类型良好协作
代码优缺点分析

优点:

  1. 统一错误处理:所有可能的错误都转换为统一的DoubleError类型
  2. 简化接口:函数返回简单的Result<i32>,DoubleError>而不是复杂的嵌套类型
  3. 关注点分离:错误生成逻辑与显示逻辑分离(通过实现Displaytrait)

局限性:

  1. 信息丢失:当前的DoubleError是空结构体,无法区分是空向量错误还是解析失败的错误。
  2. 缺乏细节:不知道具体是哪个字符串解析失败,也不知道失败原因。
改进方向

在实际项目中,通常会定义更加丰富的错误类型:

#[derive(Debug, Clone)]

enum DoubleError {

    EmptyVec,

    ParseError(String, std::num::ParseIntError),

}


impl fmt::Display for DoubleError {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        match self {

            DoubleError::EmptyVec => write!(f, "please use a vector with at least one element"),

            DoubleError::ParseError(s, e) => write!(f, "failed to parse '{}': {}", s, e),

        }

    }

}
总结

这段代码展示了Rust中自定义错误类型的基本模式:

定义自定义错误类型(结构体或枚举)

实现Displaytrait来定义错误显示方式

使用ok_or和map_err将不同的错误类型转化为统一的自定义错误类型

通过类型别名简化为Result的书写方式

这种模式提供了比简单使用字符串错误更强大、类型更安全的错误处理机制,是构建健壮Rust应用程序的基础。虽然示例中的实际比较简单,但它展示了自定义错误类型的核心概念和优势。

原文链接地址:Defining an error type - Rust By Example

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值