有没有办法在任意`&dyn std :: error :: Error`特征对象上获取SNAFU的`.backtrace()`?

时间:2019-09-20 15:01:32

标签: error-handling rust dynamic-dispatch

RFC 2504将向所有fn backtrace(&self) -> Option<&Backtrace>添加必需的std::error::Error。还没有准备好,所以现在,SNAFU(一个错误帮助程序宏)通过将ErrorCompat特征与该宏生成的所有类型绑定在一起来实现填充。这样可以在回溯到Rust每晚之前为其提供回溯支持。

但是,并非ErrorCompat的所有实现者都实现了此std::error::Error特性。我希望-在一些通用的错误打印代码中-能够显示原因链以及与实例化SNAFU错误的位置相关的堆栈跟踪。不幸的是,source()函数返回了&(dyn Error + 'static)

use std::error::Error as StdError;
use snafu::{ResultExt, ErrorCompat};

fn main() {
    let err: Result<(), _> = Err(std::io::Error::new(std::io::ErrorKind::Other, "oh no!"));

    let err = err.with_context(|| parse_error::ReadInput {
        filename: "hello"
    });

    let err = err.with_context(|| compile_error::ParseStage);

    // some generic error handling code
    if let Err(err) = err {
        // `cause` is type &(dyn std::error::Error + 'static)
        let cause = err.source().unwrap();

        if let Some(err) = /* attempt to downcast cause into &dyn snafu::ErrorCompat trait object */ {
            println!("{}", err.backtrace().unwrap());
        }
    }
}

pub mod compile_error {
    use snafu::{Snafu, Backtrace};
    #[derive(Debug, Snafu)]
    #[snafu(visibility(pub(super)))]
    pub enum Error {
        #[snafu(display("Error parsing code: {}", source))]
        ParseStage {
           source: crate::parse_error::Error,
           backtrace: Backtrace
        },
    }
}

pub mod parse_error {
    use snafu::{Snafu, Backtrace};
    #[derive(Debug, Snafu)]
    #[snafu(visibility(pub(super)))]
    pub enum Error {
        #[snafu(display("Could not read input {:?}: {}", filename, source))]
        ReadInput {
           filename: std::path::PathBuf,
           source: std::io::Error,
           backtrace: Backtrace
        },
    }
}

我看过std::any::Any::downcast_ref,但这是为了向下转换到一个结构,而不是向下将一个特性对象转换为另一个特性对象。我想避免在错误处理代码中列出所有可能的具体类型的SNAFU错误。

我可以冻结自己,直到(完全)实施RFC 2504,但是肯定有某种方法可以做到。

2 个答案:

答案 0 :(得分:1)

dyn Error具有Error的方法,仅此而已。如果无法从这些方法推断出回溯,那么该信息还能从哪里来?

不幸的是,RFC 2504尚未稳定,因此,如果要等待,则需要将其冷冻至至少Rust 1.39。

答案 1 :(得分:0)

我似乎错过了这一点,因为没有每晚重新编译std个文档,但是#![feature(backtrace)]每天晚上都在编译。 SNAFU仍然需要增加对它的支持,因此我仍然坚持让这一切正常进行。