如何使用带有盒装错误类型的“快速错误”?

时间:2016-08-09 05:41:22

标签: rust

问题描述

我试图像这样使用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(),因为它会自动成为对已实现特征的引用。也许这是我想要表达意图的语法。

1 个答案:

答案 0 :(得分:2)

as_refAsRef特征提供。请注意,as_ref通过引用收到self(标记为&self),因此要在&T上调用TAsRef必须实现std::io::ErrorAsRef没有实现这一特质。

然而,还有另一个特征看起来很像BorrowBorrowborrow提供了一种方法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" />