Rust 错误处理示例:
一、自定义返回错误信息
声明自定义错误种类的枚举体,为错误枚举体实现Display
,为每种错误实现 From
use std::num::ParseIntError;
use std::fmt;
type Result<T> = std::result::Result<T, DoubleError>;
// 定义我们的错误类型。不管对我们的错误处理情况有多重要,这些都可能自定义。
// 现在我们能够按照底层工具的错误实现,写下我们的错误,或者两者之间的内容。
#[derive(Debug)]
enum DoubleError {
// 我们不需要任何额外的信息来描述这个错误。
EmptyVec,
// 我们将推迟对于这些错误的解析错误的实现。提供额外信息将要增加更多针对类型的数据。
Parse(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"),
// 这是一个 wrapper,所以按照底层类型来给出我们的 `fmt` 实现。
// (原上:This is a wrapper so defer to the underlying types' own implementation
// of `fmt`.)
DoubleError::Parse(ref e) => e.fmt(f),
}
}
}
fn double_first(vec: Vec<&str>) -> Result<i32> {
vec.first()
// 将错误改成我们新的类型。
.ok_or(DoubleError::EmptyVec)
.and_then(|s| s.parse::<i32>()
// 在这里也更新成新的错误类型。
.map_err(DoubleError::Parse)
.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!["93", "18"];
let empty = vec![];
let strings = vec!["tofu", "93", "18"];
print(double_first(numbers));
print(double_first(empty));
print(double_first(strings));
}
二、完整的错误处理
use std::io::{Error as IoError, Read};
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::error::Error;
use std::fs::File;
use std::num::ParseIntError;
#[derive(Debug)]
enum CustomError {
ParseError(ParseIntError),
ReadError(IoError),
}
impl Display for CustomError {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
CustomError::ParseError(ref e) => e.fmt(f),
CustomError::ReadError(ref e) => e.fmt(f),
}
}
}
impl Error for CustomError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
CustomError::ParseError(ref e) => Some(e),
CustomError::ReadError(ref e) => Some(e),
}
}
}
//将IoError转为IdError::ReadError
impl From<IoError> for CustomError {
fn from(error: IoError) -> CustomError {
CustomError::ReadError(error)
}
}
//将ParseIntError转为IdError::ParseError
impl From<ParseIntError> for CustomError {
fn from(error: ParseIntError) -> CustomError {
CustomError::ParseError(error)
}
}
fn get_max_id() -> Result<i32, CustomError> {
let mut s = String::new();
File::open("id.txt")?.read_to_string(&mut s)?;
let id = s.parse::<i32>()?;
Ok(id)
}
fn main() {
let res = get_max_id();
match res{
Ok(value) => println!("读取内容为:{}",value),
Err(err) => println!("读取错误,具体错误内容为:{}",err),
}
}
三、thiserror 示例
thiserror 使用方法:https://github.com/dtolnay/thiserror
它可以使Displayand
方法的Error
实现(包括Error::source()
方法)自动化 。它甚至可以实现From特质,以允许从其他Error类型自动转换为您的类型。
use std::error::Error;
use std::fmt;
#[derive(Debug)]
enum WhoUnfollowedError {
/// Failed to complete an HTTP request.
Http { source: reqwest::Error },
/// Failed to read the cache file.
DiskCacheRead { source: std::io::Error },
/// Failed to update the cache file.
DiskCacheWrite { source: std::io::Error },
}
impl fmt::Display for WhoUnfollowedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
WhoUnfollowedError::Http { .. } => {
write!(f, "Fetch failed")
}
WhoUnfollowedError::DiskCacheRead { .. } => {
write!(f, "Disk cache read failed")
}
WhoUnfollowedError::DiskCacheWrite { .. } => {
write!(f, "Disk cache write failed")
}
}
}
}
impl Error for WhoUnfollowedError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
WhoUnfollowedError::Http { source } => Some(source),
// The "disk" variants both have the same type for their source
// fields so we can group them up in the same match arm.
WhoUnfollowedError::DiskCacheRead { source }
| WhoUnfollowedError::DiskCacheWrite { source } => Some(source),
}
}
}
impl From<reqwest::Error> for WhoUnfollowedError {
fn from(other: reqwest::Error) -> WhoUnfollowedError {
WhoUnfollowedError::Http { source: other }
}
}
果使用thiserror,则WhoUnfollowedError代码如下所示:
use thiserror::Error;
#[derive(Error, Debug)]
enum WhoUnfollowedError {
#[error("Failed to complete an HTTP request")]
Http { #[from] source: reqwest::Error },
#[error("Failed to read the cache file")]
DiskCacheRead { source: std::io::Error },
#[error("Failed to update the cache file")]
DiskCacheWrite { source: std::io::Error },
}