尝试向下转换时出现终身错误

Shm*_*opy 4 downcast rust

我有一个正在尝试遍历的错误链接列表。给定MyError,它是带有可选代码的错误链接列表,我的目标是遍历该链并返回第一个非None代码:

type BoxedError = Box<dyn std::error::Error + Send + Sync + 'static>;

#[derive(Debug)]
struct MyError {
    code: Option<u32>,
    source: Option<BoxedError>,
}

impl std::error::Error for MyError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        self.source().map(|s| s as _)
    }
}

impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Display::fmt("", f)
    }
}

impl MyError {
    fn source(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
        self.source.as_ref().map(|c| c.as_ref())
    }

    fn traverse(&self) -> Option<u32> {
        use core::any::Any;
        if let Some(code) = self.code {
            return Some(code);
        }    
        if let Some(source) = self.source() {
            let as_any = &source as &dyn Any;
            if let Some(myerr) = as_any.downcast_ref::<MyError>() {
                return myerr.traverse();
            }
        }
        None
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生以下错误:

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> src/lib.rs:31:36
   |
26 |     fn traverse(&self) -> Option<u32> {
   |                 ----- this data with an anonymous lifetime `'_`...
...
31 |         if let Some(source) = self.source() {
   |                               ---- ^^^^^^
   |                               |
   |                               ...is used here...
32 |             let as_any = &source as &dyn Any;
   |                          ------- ...and is required to live as long as `'static` here

For more information about this error, try `rustc --explain E0759`.
error: could not compile `playground` due to previous error
Run Code Online (Sandbox Code Playgroud)

我不确定为什么这里会出现生命周期错误,因为源函数返回一个静态特征对象(这意味着该对象后面没有其他引用,对吧?)。

tre*_*tcl 5

&source as &dyn Any不按你的想法做。source类型为&(dyn std::error::Error + Send + Sync + 'static),因此必须擦除该类型才能强制转换&source为&dyn Any。

该+ 'static类型中的 仅仅意味着被引用的类型(实现 的类型Error + Send + Sync)必须不包含非'static引用。still&有自己的生命周期,但它不是'static(也不可能有,因为它是从 借用的self)。正是该引用的生命周期阻止&(dyn std::error::Error + Send + Sync + 'static)了'static.

你想做的是source as &dyn Any,如果它有效的话,将会升级dyn Error到dyn Any。但这是不可能的,因为Any不是 的超特征Error。此外,即使确实Error有Any作为超级特征,Rust 目前也不支持这样的强制转换。

特征升级可在每晚的功能标志下使用,但您不需要它。使用自身downcast定义的方法dyn Error,添加这些方法是为了支持此用例。

if let Some(myerr) = source.downcast_ref::<MyError>() {
    return myerr.traverse();
}
Run Code Online (Sandbox Code Playgroud)

如果您需要向下转换一个不是的特征对象dyn Error,您将需要找到一个解决方法。