Traits & Generics

Shared behaviour with traits, generic functions with trait bounds, and dyn trait objects.

A trait describes behaviour a type can have — like an interface. Generic code is written against traits, and the compiler produces fast, specialized code for each concrete type. When different types must live in the same collection, trait objects (dyn Trait) provide dynamic dispatch.

Sensors behind a trait

trait Sensor requires name and read and provides a default report.

Accelerometer overrides report; Thermistor uses the default.

print_twice<S: Sensor> accepts any Sensor; the compiler generates one copy per type (monomorphization).

Vec<Box<dyn Sensor>> holds different sensor types; each call goes through a vtable at run time.

largest works for any type that can be compared (PartialOrd), copied and printed.

Important standard traits

fn largest<T>(items: &[T]) -> T {... items[0] >... } fn largest<T: PartialOrd + Copy>(items: &[T]) -> T {... }

Without the bound, the compiler does not know that T supports > or can be copied out of the slice. Bounds state exactly what the code needs.

What is the difference between impl Trait/generics and dyn Trait?

Generics (and impl Trait) are resolved at compile time: a specialized copy per type, no run-time cost. dyn Trait is resolved at run time through a vtable, allowing different types behind one pointer (e.g. in a Vec).