如何正确实现Error :: cause?

chr*_*dou 5 reference traits option rust

我在实现这个Error特性时遇到了问题.我想从Diesel或其他数据库驱动程序中包装错误.我甚至没有接近实施,From因为我已经失败了实施Error.导致代码无法编译的行是代码块最后的那一行.

use std::fmt;
use std::error::{self, Error};

#[derive(Debug)]
pub enum MyError {
    NotFound(String),
    PersistenceError(Box<Error + Send + Sync>),
}

pub type MyResult<T> = Result<T, MyError>;

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MyError::NotFound(ref msg) => write!(f, "Not found: {}", msg),
            MyError::PersistenceError(ref cause) => write!(f, "Persistence error: {}", cause),
        }
    }
}

impl Error for MyError {
    fn description(&self) -> &str {
        match *self {
            MyError::NotFound(ref msg) => msg,
            MyError::PersistenceError(ref cause) => cause.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            MyError::NotFound(_) => None,
            // `*cause` does not live long enough
            MyError::PersistenceError(cause) => Some(&*cause),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

*原因不够长

MyError::PersistenceError(cause) => Some(&*cause),
Run Code Online (Sandbox Code Playgroud)

对于类型std :: error :: Error + Send + Sync +'static [E0277],没有实现trait core :: marker :: Sized

MyError::PersistenceError(ref cause) => Some(cause),
Run Code Online (Sandbox Code Playgroud)

对于类型`&Box,没有实现trait std :: error :: Error

MyError::PersistenceError(ref cause) => Some(&cause)
Run Code Online (Sandbox Code Playgroud)

但这些都没有奏效.

She*_*ter 6

在这种情况下打印变量类型很有用:

match *self {
    MyError::NotFound(_) => None,
    MyError::PersistenceError(ref cause) => {
        let () = cause;
    },
}
Run Code Online (Sandbox Code Playgroud)

这会告诉你这cause是一个&Box<std::error::Error + Send + Sync>.

如果我们取消引用它一次,我们将有一个Box<std::error::Error + Send + Sync>,如果我们第二次取消引用它们将有一个std::error::Error + Send + Sync(这不是一个真正的类型).然后我们可以采用另一个可以隐含地形成的参考&Error:

match *self {
    MyError::NotFound(_) => None,
    MyError::PersistenceError(ref cause) => Some(&**cause),
}
Run Code Online (Sandbox Code Playgroud)