Appearance
33.5 新的 Failure 库
标准库中现存的 Error trait 有几个明显问题:
description 方法基本没什么用;
无法回溯,它没有记录一层层的错误传播的过程,不方便 debug;
Box<Error>
不是线程安全的。
Failure 这个库就是为了进一步优化错误处理而设计的。它主要包含三个部分。
新的
failure::Fail
trait,是为了取代std::error::Error
trait 而设计的。它包含了更丰富的成员方法,且继承于 Send+Sync,具备线程安全特性。自动 derive 机制,主要是让编译器帮用户写一些重复性的代码。
failure::Error
结构体。所有其他实现了 Fail trait 的错误类型,都可以转换成这个类型,而且它提供了向下转型的方法。
使用 failure 来实现前面那个示例,代码如下:
rust
#[macro_use]
extern crate failure;
use std::fs::File;
use std::io::Read;
use std::path::Path;
#[derive(Debug, Fail)]
enum MyError {
#[fail(display = "IO error {}.", _0)]
Io(#[cause] std::io::Error),
#[fail(display = "Parse error {}.", _0)]
Parse(#[cause] std::num::ParseIntError),
}
impl From<std::io::Error> for MyError {
fn from(error: std::io::Error) -> Self {
MyError::Io(error)
}
}
impl From<std::num::ParseIntError> for MyError {
fn from(error: std::num::ParseIntError) -> Self {
MyError::Parse(error)
}
}
fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, MyError> {
let mut file = File::open(file_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let n = contents.trim().parse::<i32>()?;
Ok(2 * n)
}
fn main() {
match file_double("foobar") {
Ok(n) => println!("{}", n),
Err(err) => println!("Error: {:?}", err),
}
}
现在社区里已经有一些库转向使用 failure 做错误处理。它将来可能是 Rust 生态系统中主流的错误处理方式。