What does it mean when we let a trait inherits 'static?

Viewed 236

Rust supports trait inheritance, as follows:

pub trait A {}
pub trait B: A {}

B: A means that if some type T implements B, it also needs to implement all the methods in A.

But today I see the following code:

trait Display: 'static {
    fn print(&self);
}

What does it mean? It doesn't seem to be trait inheritance.

2 Answers

Rust supports trait inheritance, as follows [...] B: A means that if some type T implements B, it also needs to implement all the methods in A.

Technically, that is not inheritance but requirement. It is a trait bound not entirely dissimilar to one you'd have in a function: it constraints the type on which B is implementable to only types on which A is already implemented.

With that change in wording, the second version is much easier to understand: it's a lifetime bound, meaning it constraints the type on which B is implementable to only types with 'static lifetime, meaning if you're trying to implement B on a type, that must either have no lifetime at all, or have a 'static lifetime (or the implementation must have a lifetime bound aka only work for some uses of the type).

You can see that if you try to implement the trait on a lifetime-generic structure:

struct A<'a>(&'a str);
trait Display: 'static {
    fn print(&self);
}

impl <'a>Display for A<'a> {
    fn print(&self) { todo!() }
}

will yield

error[E0478]: lifetime bound not satisfied

That is because 'a can be anything, so implementing Display for A<'a> means it is also implemented for non-'static instances, which is not valid.

By adding the relevant lifetime bound on the impl, and thus limiting the implementation to A<'static> instances:

struct A<'a>(&'a str);
trait Display: 'static {
    fn print(&self);
}

impl <'a: 'static>Display for A<'a> {
    fn print(&self) { todo!() }
}

the requirements of the trait are satisfied, and the impl is valid (nb: the 'a is not necessary here you can just impl ... for A<'static>, I'm showing it for regularity).

And if your struct has no lifetime it works by default, because no lifetime ~ 'static:

struct A(String);
trait Display: 'static {
    fn print(&self);
}

impl Display for A {
    fn print(&self) { todo!() }
}

Rust doesn't have inheritance.

What it has is a way to define constraints. For example a trait may be constrained to only be implemented by types which implement another trait.

In your case the constraint is a lifetime bound.

To implement your Display trait, an object may contain references but in this case their lifetime must respect this constraint.

Let's suppose you have this type:

struct S<'a> {
    s: &'a str,
}

Then you can't implement the trait for any lifetime, but only 'static.

impl Display for S<'static> {
    fn print(&self){}
}

fn main() {
    let s1 = "test";
    let a = S { s: s1 };
    a.print(); // compiles

    let s2 = "test".to_string();
    let a = S { s: &s2 };
    a.print(); // doesn't compile because s doesn't live long enough
}

Related