liveBook · Manning

Trait object

As explained in Idiomatic Rust

A trait object is a dynamically dispatched Rust value accessed through a trait interface rather than its concrete type.

A trait object lets different concrete Rust types be used through one trait interface. Write `dyn Trait` where a concrete type would otherwise appear. Calls through that interface use dynamic dispatch: Rust looks up the implementation at run time through a compiler-generated vtable. This resembles virtual-method dispatch, but it does not make the types part of an inheritance hierarchy. section 2.2.6

Trait objects are unsized, so a `Vec<dyn MyTrait>` cannot hold them directly. Put each value behind a suitable smart pointer instead: `Vec<Box<dyn MyTrait>>`. `Box` permits an unsized target through its `?Sized` bound; ordinary generic type parameters require `Sized` by default. section 2.2.6

One vector, two implementations

Implement `MyTrait::trait_hello` for `MyStruct1` and `MyStruct2`, then push a boxed instance of each into `Vec<Box<dyn MyTrait>>`. Iterating over the vector can call `trait_hello()` on both values. It cannot call either struct’s separate `struct_hello()` method through the trait interface. section 2.2.6

Listing 10.11 Testing the polymorphism with trait objects
fn main() {
    let dog = Box::new(Dog::new("Rusty"));
    let cat = Box::new(Cat::new("Misty"));

    let animals: Vec<Box<dyn Animal>> = vec![dog, cat];

    for animal in animals {
        println!("{} says {}", animal.name(), animal.speak());
    }
}

See `Dog` and `Cat` stored as `Box<dyn Animal>` values and called through their shared `Animal` methods. section 10.6

If concrete-type behavior is needed, a trait can expose `&dyn Any` and callers can try `downcast_ref` for a particular type. Prefer the shared trait methods when they express the behavior you need. section 2.2.6

Use trait objects for this kind of mixed collection rather than implementing `Deref` to make one struct look like another. `Deref`-based imitation of a superclass is misleading; a trait states the shared interface directly. Dynamic dispatch is a tool, not a rule for every design. section 10.6 section 2.2.6

How Idiomatic Rust covers it

How deep it goes
Explains `dyn`, vtable dispatch, unsized storage, `Box` bounds, and optional downcasting to concrete types.
Examples
Shows boxed implementations in a vector and `Dog` and `Cat` speaking through `Box<dyn Animal>`.
What it assumes
Assumes familiarity with traits, structs, and vectors while explaining why trait objects need suitable pointer storage.
What you can do after
Build it from scratch with `Vec<Box<dyn Trait>>` and call shared methods without treating `Deref` as inheritance.
How it connects
Connects trait objects to traits, dynamic dispatch, vtables, `Sized`, smart pointers, downcasting, and `Deref` misuse.

Also explained in

Compare how 4 books explain trait object →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.