#error #macro #failure #error-message

no-std custom_error_core

使用 custom_error! 宏定义自定义错误,无需编写大量样板代码

2 个稳定版本

1.9.0 2021 年 4 月 7 日
1.8.1 2021 年 4 月 6 日

#811Rust 模式

BSD-2-Clause

39KB
761

Rust 自定义错误

此软件包包含一个宏,可以帮助您定义自定义错误,而无需编写大量样板代码。

此软件包中包含的 custom_error! 宏接受一个类型名和可能的错误列表,并为所有情况生成 Rust 枚举,以及实现 std::error::Errorstd::fmt::Display 的所需 impl 块。

如果您只有一个错误情况,您也可以生成一个结构体而不是枚举。

现在您可以这样写

extern crate custom_error;
use custom_error::custom_error;

// Note the use of braces rather than parentheses.
custom_error!{MyError
    Unknown{code:u8} = "unknown error with code {code}.",
    Err41            = "Sit by a lake"
}

而不是

#[derive(Debug)]
enum MyError {
    Unknown { code: u8 },
    Err41,
}

impl std::error::Error for MyError {}

impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter)
    -> std::fmt::Result {
        match self {
            MyError::Unknown { code } => write!(f, "unknown error with code {}." , code),
            MyError::Err41 => write!(f, "Sit by a lake")
        }
    }
}

如果您只有一个错误情况,您也可以生成一个结构体

extern crate custom_error;
use custom_error::custom_error;

custom_error!{MyError{code:u8} = "error with code {code}."}

简单错误

要定义一个简单错误,您只需指出以下三个内容

  • 您的自定义错误类型的名称,
  • 不同错误情况的名称,
  • 每个情况的人类可读描述。
extern crate custom_error;
use custom_error::custom_error;

custom_error!{MyError
    Bad      = "Something bad happened",
    Terrible = "This is a very serious error!!!"
}

带参数的自定义错误

您可以在错误中存储数据。为了做到这一点,在错误类型之后用花括号指示要存储的字段名称和类型。

extern crate custom_error;
use custom_error::custom_error;

custom_error!{SantaError
    BadChild{name:String, foolishness:u8} = "{name} has been bad {foolishness} times this year",
    TooFar                                = "The location you indicated is too far from the north pole",
    InvalidReindeer{legs:u8}              = "The reindeer has {legs} legs"
}

assert_eq!(
    "Thomas has been bad 108 times this year",
    SantaError::BadChild{name: "Thomas".into(), foolishness: 108}.to_string());

错误消息可以使用花括号({parameter_name})引用您的参数。如果您需要一些自定义逻辑来显示您的参数,您可以使用 高级自定义错误消息

包装其他错误类型

如果您的错误原因是另一个更底层的错误,您可以通过在您的错误情况之一中添加一个特殊的 source 字段来指示这一点。

因此,您可以使您的自定义错误包装其他错误类型,并且将这些外部错误类型的转换将自动实现。

#[macro_use] extern crate custom_error;
use std::{io, io::Read, fs::File, result::Result, num::ParseIntError};

custom_error! {FileParseError
    Io{source: io::Error}         = "unable to read from the file",
    Format{source: ParseIntError} = "the file does not contain a valid integer",
    TooLarge{value:u8}            = "the number in the file ({value}) is too large"
}

fn parse_hex_file(filename: &str) -> Result<u8, FileParseError> {
    let mut contents = String::new();
    // The '?' notation can convert from generic errors to our custom error type
    File::open(filename)?.read_to_string(&mut contents)?;
    let value = u8::from_str_radix(&contents, 16)?;
    if value > 42 {
        Err(FileParseError::TooLarge { value })
    } else {
        Ok(value)
    }
}

fn main() {
    let parse_result = parse_hex_file("/i'm not a file/");
    assert_eq!("unable to read from the file", parse_result.unwrap_err().to_string());
}

可见性

您可以在声明开始处添加 pub 关键字,以使错误类型公开。

custom_error!{pub MyError A="error a", B="error b"}

属性

您可以通过在宏调用开始处添加属性来为您错误类型推导特性。

custom_error!{#[derive(PartialEq,PartialOrd)] MyError A="error a", B="error b"}
assert!(MyError::A < MyError::B);

由于文档注释仅仅是#[doc = "..."]语法的糖,因此您也可以使用它们。

custom_error!{
   /// This is the documentation for my error type
   pub MyError A="error a", B="error b"
}

高级自定义错误信息

如果您想使用无法用简单的格式化字符串表示的错误信息,您可以使用自定义代码生成错误信息。

在下面的示例中,我们使用这个特性来根据底层IO错误的根本原因显示不同的错误信息。

custom_error!{ pub MyError
    Io{source: Error} = @{
        match source.kind() {
            NotFound => "The file does not exist",
            TimedOut => "The operation timed out",
            _ => "unknown error",
        }
    },
    Unknown = "unknown error"
}

无运行时依赖

特性