2 个稳定版本
1.9.0 | 2021 年 4 月 7 日 |
---|---|
1.8.1 | 2021 年 4 月 6 日 |
#811 在 Rust 模式
39KB
761 行
Rust 自定义错误
此软件包包含一个宏,可以帮助您定义自定义错误,而无需编写大量样板代码。
此软件包中包含的 custom_error!
宏接受一个类型名和可能的错误列表,并为所有情况生成 Rust 枚举,以及实现 std::error::Error
和 std::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"
}