dyn Trait lifetimes and Box<dyn Trait>

Every trait object (dyn Trait) has an elide-able lifetime with it's own defaults when completely elided. This default is stronger than the normal function signature elision rules. The most common way to run into a lifetime error about this is with Box<dyn Trait> in your function signatures, structs, and type aliases, where it means Box<dyn Trait + 'static>.

Often the error indicates that non-'static references/types aren't allowed in that context, but sometimes it means that you should add an explicit lifetime, like Box<dyn Trait + 'a> or Box<dyn Trait + '_>.

The latter will act like "normal" lifetime elision; for example, it will introduce a new anonymous lifetime parameter as a function input parameter, or use the &self lifetime in return position.

The reason the lifetime exists is that coercing values to dyn Trait erases their base type, including any lifetimes that it may contain. But those lifetimes have to be tracked by the compiler somehow to ensure memory safety. The dyn Trait lifetime represents the maximum lifetime the erased type is valid for.


Some short examples:

#![allow(unused)]
fn main() {
trait Trait {}

// The return is `Box<dyn Trait + 'static>` and this errors as there
// needs to be a bound requiring `T` to be `'static`, or the return
// type needs to be more flexible
fn one<T: Trait>(t: T) -> Box<dyn Trait> {
    Box::new(t)
}

// This works as we've added the bound
fn two<T: Trait + 'static>(t: T) -> Box<dyn Trait> {
    Box::new(t)
}

// This works as we've made the return type more flexible.  We still
// have to add a lifetime bound.
fn three<'a, T: Trait + 'a>(t: T) -> Box<dyn Trait + 'a> {
    Box::new(t)
}
}

For a more in-depth exploration, see this section of the dyn Trait tour.