bhylu.com

Advertisements

Rust Trait Objects

Choose dynamic dispatch when one collection needs different concrete types.

How it works

A trait object uses a trait interface behind a pointer and selects the concrete implementation at runtime. It can represent different types in one collection when the trait supports dynamic dispatch. This differs from a generic function specialised for concrete types. Consider allocation, ownership and the trait’s allowed methods when choosing a design rather than treating dynamic dispatch as a universal abstraction.

Run the code

Reviewed with Rust 1.97.0, edition 2024, using the standard library only. Save the complete download as lesson-name.rs in a separate learning folder, compile with rustc --edition=2024 lesson-name.rs and run the resulting program (lesson-name.exe on Windows). Use the actual lesson filename. The final project includes complete Cargo package files; run cargo test --offline and cargo run --offline from that separate package folder. There is no Rust browser runner; PHP, Apache and MySQL are not needed.

This complete example was executed in the stated local review environment.

Download complete source

Example

trait-objects.rs

fn main() {
    trait Label { fn label(&self) -> &str; }
    struct Tray;
    struct Basket;
    impl Label for Tray { fn label(&self) -> &str { "tray" } }
    impl Label for Basket { fn label(&self) -> &str { "basket" } }
    let items: Vec<Box<dyn Label>> = vec![Box::new(Tray), Box::new(Basket)];
    assert_eq!(items.iter().map(|x| x.label()).collect::<Vec<_>>(), vec!["tray","basket"]);
    println!("Dynamic labels: tray, basket");
}

Expected result

Dynamic labels: tray, basket

Each Box owns a different concrete value while exposing the same Label interface. The returned text is borrowed for the call and is not an independently owned String. A simple enum might be preferable if the set of variants is closed and exhaustive matching is valuable.

Primary technical reference: Rust documentation.