liveBook · Manning

Trait object

As explained in Rust in Action: Systems programming concepts and techniques

A trait object is a dynamically sized Rust value representing a value of a type that implements a trait and accessed through a pointer for runtime polymorphism.

A trait object lets Rust use values of different concrete types through one shared trait interface. Method calls use dynamic dispatch: the method to run is selected at runtime. This is useful when a collection must hold different types, or a function must return different error types. section 8.3.1 section 8.3.2 section 8.3.3

Trait objects are dynamically sized, so they appear behind pointers:

  • &dyn Trait borrows a value through the trait interface. section 8.3.2
  • &mut dyn Trait borrows a value mutably through the trait interface. section 8.3.2
  • Box<dyn Trait> owns the trait object. The Box pointer has a known size even when the value it points to does not. section 8.3.2 section 8.5.1

A party with different character types

Suppose Dwarf, Human, and Elf each implement Enchanter. A Vec needs one element type, so store references through their shared trait instead: `let party: Vec<&dyn Enchanter> = vec![&d, &h, &e];`. A randomly chosen member can then receive an `enchant` call. The caller uses the trait interface rather than the chosen character’s concrete type. section 8.3.1 section 8.3.3

One return type for different errors

An HTTP request can use `fn main() -> Result<(), Box<dyn Error>>`. The same pattern helps when `File::open()` and IPv6 address parsing can produce different errors: `?` can propagate them through one boxed error type. The trade-off is type erasure—the return type no longer identifies which upstream error type occurred. If later code must distinguish them, an enum wrapper can preserve them as variants. section 8.2 section 8.5.1 section 8.5.2

Generics offer the contrasting choice: static dispatch and faster runtimes, but potentially more compiled code. Trait objects add a small runtime cost through pointer indirection while allowing a single compiled version of a function. Use the trade-off that fits the job. section 8.3.2 section 8.11

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Explains pointer forms, ownership, dynamic dispatch, size, and runtime trade-offs through examples, without detailing dispatch internals.
Examples
Uses a mixed-type role-playing party, an HTTP GET request, and file-opening plus IPv6-parsing errors.
What it assumes
Introduces trait objects by their purpose while using structs, traits, Vec, Result, and references in working Rust examples.
What you can do after
Build it from scratch: store different implementors behind one trait interface and return multiple error types through Box<dyn Error>.
How it connects
Connects trait objects to generics, dynamic dispatch, type erasure, Vec, Result, and error handling.

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 Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.