为什么从特征对象的 impl 中的方法返回的引用需要静态生命周期?

Why is 'static lifetime required for references returned from methods in an impl for a trait object?

当我不在此代码中包含 + 'static 时,rustc 会抱怨。为什么?

// adapted from rust-analyzer https://github.com/rust-analyzer/rust-analyzer
trait Upcast<T: ?Sized> {
    fn upcast(&self) -> &T;
}

trait DefDatabase {}
trait HirDatabase: Upcast<dyn DefDatabase> {}

struct RootDatabase{}
impl Upcast<dyn DefDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn DefDatabase + 'static) {
        &*self
    }
}
`impl` item signature doesn't match `trait` item signature
expected `fn(&RootDatabase) -> &(dyn DefDatabase + 'static)`
   found `fn(&RootDatabase) -> &dyn DefDatabase`
the lifetime requirements from the `impl` do not correspond to the
requirements in the `trait`
verify the lifetime relationships in the `trait` and `impl` between the
`self` argument, the other inputs and its output

为什么需要 'static 生命周期?

看来 dyn 对这个例子来说是必不可少的。 rustc 没有抱怨这个 impl,它没有提到 'static:

impl Upcast<RootDatabase> for RootDatabase {
    fn upcast(&self) -> &Self {
        self
    }
}

您需要明确说明 Trait 对象 &'dyn DefDatabase 的生命周期,以便借用检查器知道后面的结构持有的任何引用的生命周期指针是。 'static 是默认的,如果你没有定义它,或者它不能从上下文中确定。有关详细信息,请参阅 Rust 语言参考中的 default trait object lifetimes

为您的 Upcast 特征定义添加生命周期允许您删除 'static

trait Upcast<'a, T: ?Sized + 'a> {
    fn upcast(&self) -> &T; // 'a is not necessary here because the generic `T` may or may not be a trait object
}

trait DefDatabase {}

struct RootDatabase{}
impl DefDatabase for RootDatabase {}

impl<'a> Upcast<'a, dyn DefDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn DefDatabase + 'a) { // now we can replace 'static with 'a
        &*self
    }
}

impl<'a> Upcast<'a, RootDatabase> for RootDatabase {
    fn upcast(&self) -> &Self { // &Self is not a trait object, so no trait object lifetime is necessary
        self
    }
}

编辑:

需要注意的是这个生命周期是不是引用trait对象的生命周期,可以单独声明和是为什么生命周期必须用括号来消除歧义的原因。

impl<'a> Upcast<'a, dyn DefDatabase> for RootDatabase {
    fn upcast<'b>(&'b self) -> &'b (dyn DefDatabase + 'a) { // 'b is elided
        &*self
    }
}