例如:
extern crate failure;
use std::fs::File;
fn f() -> std::result::Result<(), failure::Error>
let _ = File::open("test")?;
"123".parse::<u32>()?;
Ok(())
}
什么是允许failure::Error
能够表示std::io::Error
,解析错误和任何其他自定义错误类型的技术?重新创建此功能的最小实现是什么?
这里有两种机制。
第一个机制是问号运算符,returns Err(From::from(e))
when it encounters an Err(e)
。如果函数返回类型是Result<T, E>
,这允许我们返回F
实现E
的任何错误类型From<F>
。
从failure::Error
类型的文档,我们可以看到有一个generic From
implementation for all types implementing the failure::Fail
trait,并有一个generic implementation of Fail
for all types implementing std::error::Error
(只要它们也是Send + Sync + 'static
)。结合起来,这允许我们返回任何实现failure::Fail
特征或std::error::Error
特征的类型。标准库中的所有错误类型都实现了Error
特征,包括std::io::Error
和std::num::ParseIntError
。
这已经解释了代码编译的原因,但它没有解释转换如何在内部工作。这可以通过游戏中的第二种机制 - 特征对象来解释。 Error
箱中failure
类型的(略微编辑)定义如下:
struct Error {
imp: ErrorImpl,
}
struct ErrorImpl {
inner: Box<Inner<dyn Fail>>,
}
struct Inner<F: ?Sized + Fail> {
backtrace: Backtrace,
failure: F,
}
Inner
类型将错误存储为使用动态调度进行方法调用的特征对象。
failure::Error::from_boxed_compat
构造函数用于将任何错误转换为failure::Error
。
pub fn from_boxed_compat(err: Box<dyn StdError + Sync + Send + 'static>) -> Error
这个函数接受任何将错误作为输入的结构并构造一个failure::Error
https://docs.rs/failure/0.1.5/failure/struct.Error.html#impl
failure::Error
在其中包含一个堆存储的trait对象,它可以存储实现Error对象的结构。
struct ErrorImpl {
inner: Box<Inner<Fail>>,
}
此外,看起来Fail trait
实现了许多错误。 ?
运算符将添加一个into
方法,将错误转换为failure::Error