我试图像这样使用quick_error:
#[macro_use] extern crate quick_error;
use std::error::Error;
use std::io;
fn main() {
quick_error!{
#[derive(Debug)]
pub enum MyError {
Io(err: io::Error) {
cause(err)
}
Any(err: Box<Error>) {
cause(err)
}
}
}
}
即使有许多其他错误变体,我最感兴趣的是可以通过装箱来处理任何类型的错误。
但是,上面的代码不适用于盒装类型:
error[E0277]: the trait bound `std::error::Error + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:11:23
|
11 | cause(err)
| ^^^
在查看生成的代码时(使用cargo expand
),为什么会这样变得更加明显:
#[allow(unused)]
impl ::std::error::Error for MyError {
[...]
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
MyError::Io(ref err) => Some(err),
MyError::Any(ref err) => Some(err),
}
}
}
&Box<Error>
不会自动成为&Error
,除非您专门致电err.as_ref()
。
因此下面的代码可以工作,我只是通过使用rustc编译扩展的,调整后的版本来尝试它。
#[allow(unused)]
impl ::std::error::Error for MyError {
[...]
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
MyError::Io(ref err) => Some(err),
// ------> note the *as_ref()* <------
MyError::Any(ref err) => Some(err.as_ref()),
}
}
}
如何才能完成上述工作?
对我而言,修改quick-error
是可行的,但是,例如,不允许在.as_ref()
上调用&std::io::Error
,这似乎是quick-error
的简单修复:
#[allow(unused)]
impl ::std::error::Error for MyError {
[...]
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
MyError::Io(ref err) => Some(err.as_ref()),
MyError::Any(ref err) => Some(err.as_ref()),
}
}
}
以上原因导致此错误:
error: no method named `as_ref` found for type `&std::io::Error` in the current scope
--> expanded.rs:91:50
|
91 | MyError::Io(ref err) => Some(err.as_ref()),
| ^^^^^^
|
= note: the method `as_ref` exists but the following trait bounds were not satisfied: `std::io::Error : core::convert::AsRef<_>
它确实让我想知道为什么我不能在任何引用上使用&std::io::Error.as_ref()
,因为它会自动成为对已实现特征的引用。也许这是我想要表达意图的语法。
答案 0 :(得分:2)
as_ref
由AsRef
特征提供。请注意,as_ref
通过引用收到self
(标记为&self
),因此要在&T
上调用T
,AsRef
必须实现std::io::Error
。 AsRef
没有实现这一特质。
然而,还有另一个特征看起来很像Borrow
:Borrow
。 borrow
提供了一种方法as_ref
,其签名与Borrow
相同。 impl<T> Borrow<T> for T where T: ?Sized
也有一组不同的实现者;值得注意的是,它有borrow
。这意味着对于每种类型,我们可以调用Borrow
方法(假设use
特征带入Borrow<T>
的范围)以获取对相同的类型。 Box<T>
也实现了T
,因此您可以从Box<T>
借用#[allow(unused)]
impl ::std::error::Error for MyError {
fn cause(&self) -> Option<&::std::error::Error> {
use std::borrow::Borrow;
match *self {
MyError::Io(ref err) => Some(err.borrow()),
MyError::Any(ref err) => Some(err.borrow()),
}
}
}
,对其他指针/智能指针类型也是如此。
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />