Rust 错误处理(二)


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 },
}

拓展阅读
anyhow和thiserror - 错误处理库
适用于Pythonista的Rust错误处理

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页