Course contentsShow
← Rust
Lesson 578 of 1,9105. Type System and TraitsFree lesson

Handling Trait Object Lifetimes

Manage reference lifetimes when working with dynamic dispatch and trait objects.

In this lesson, you will learn how to safely manage reference lifetimes when using trait objects to ensure your dynamic dispatch doesn't lead to dangling pointers.

The Lifetime Problem with dyn Trait

When you use a trait object like &dyn MyTrait, Rust needs to ensure that the underlying data lives at least as long as the reference to the trait object. Because a dyn Trait is a "fat pointer" (storing both the data pointer and the vtable pointer), the compiler must decide how long the data inside that pointer is guaranteed to exist.

If you don't specify a lifetime, Rust assumes a default. For a bare trait object &dyn Trait, the compiler defaults to the lifetime of the reference itself, denoted as &'a dyn Trait. However, if your trait object is part of a struct, you must be explicit.

Explicit Lifetime Annotations

Consider a scenario where you store a trait object inside a struct. The compiler needs to know that the struct cannot outlive the data it refers to.

trait Speaker {
    fn say(&self);
}

struct Logger<'a> {
    // We explicitly tell the compiler the trait object 
    // lives at least as long as 'a
    target: &'a dyn Speaker,
}

Without the 'a annotation, the compiler would complain because it wouldn't know if the target might be dropped while the Logger is still alive. By adding the lifetime, you create a contract: the Logger cannot exist longer than the Speaker it holds.

When to use 'static

Sometimes, you might see Box<dyn Trait + 'static>. This means the trait object must contain only types that do not hold any non-static references. This is common when you want to store a trait object in a collection that persists for the entire duration of the program, or when you need to send the trait object across threads. If your data contains references (like the Logger example above), it cannot satisfy a 'static bound.

Always check if your trait object is "borrowing" data from another scope or "owning" the data. If it borrows, specify the lifetime; if it owns (via Box), you may need to consider if that data needs to be 'static.

Key Takeaway: A trait object dyn Trait is a reference that requires an explicit lifetime annotation whenever it is stored in a struct or passed in a way where the compiler cannot infer its duration.