Reputation: 15502
When I don't include the + 'static
in this code, rustc
complains. Why?
// 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
Why is 'static
lifetime required?
It seems like the dyn
is essential to the example. rustc
does not complain about this impl, which doesn't mention 'static
:
impl Upcast<RootDatabase> for RootDatabase {
fn upcast(&self) -> &Self {
self
}
}
Upvotes: 2
Views: 728
Reputation: 46
You need to explicitly state what the lifetime of the Trait Object &'dyn DefDatabase
is so that the borrow checker knows what the lifetime of any references held by the struct behind the pointer are. 'static
is the default if you do not define it, or it cannot otherwise be determined from the context. See default trait object lifetimes in the rust language reference for more information.
Adding a lifetime to your Upcast
trait definition allows you to drop '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
}
}
Edit:
It should be noted that this lifetime is not the lifetime of the reference to the trait object, which can be declared separately and is the reason for why the lifetime must be disambiguated with parenthesis.
impl<'a> Upcast<'a, dyn DefDatabase> for RootDatabase {
fn upcast<'b>(&'b self) -> &'b (dyn DefDatabase + 'a) { // 'b is elided
&*self
}
}
Upvotes: 3