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,但是肯定有某种方法可以做到。
答案 0 :(得分:1)
dyn Error
具有Error
的方法,仅此而已。如果无法从这些方法推断出回溯,那么该信息还能从哪里来?
不幸的是,RFC 2504尚未稳定,因此,如果要等待,则需要将其冷冻至至少Rust 1.39。
答案 1 :(得分:0)
我似乎错过了这一点,因为没有每晚重新编译std
个文档,但是#![feature(backtrace)]
每天晚上都在编译。 SNAFU仍然需要增加对它的支持,因此我仍然坚持让这一切正常进行。