Trait Objects
Trait objects allow for values of different types, for instance in a collection:
struct Dog { name: String, age: i8, } struct Cat { lives: i8, } trait Pet { fn talk(&self) -> String; } impl Pet for Dog { fn talk(&self) -> String { format!("Woof, my name is {}!", self.name) } } impl Pet for Cat { fn talk(&self) -> String { String::from("Miau!") } } fn main() { let pets: Vec<Box<dyn Pet>> = vec![ Box::new(Cat { lives: 9 }), Box::new(Dog { name: String::from("Fido"), age: 5 }), ]; for pet in pets { println!("Hello, who are you? {}", pet.talk()); } }
Memory layout after allocating pets:
This slide should take about 10 minutes. 
                    - Types that implement a given trait may be of different sizes. This makes it
impossible to have things like Vec<dyn Pet>in the example above.
- dyn Petis a way to tell the compiler about a dynamically sized type that implements- Pet.
- In the example, petsis allocated on the stack and the vector data is on the heap. The two vector elements are fat pointers:- A fat pointer is a double-width pointer. It has two components: a pointer to
the actual object and a pointer to the virtual method table (vtable) for
the Petimplementation of that particular object.
- The data for the Dognamed Fido is thenameandagefields. TheCathas alivesfield.
 
- A fat pointer is a double-width pointer. It has two components: a pointer to
the actual object and a pointer to the virtual method table (vtable) for
the 
- Compare these outputs in the above example:
println!("{} {}", std::mem::size_of::<Dog>(), std::mem::size_of::<Cat>()); println!("{} {}", std::mem::size_of::<&Dog>(), std::mem::size_of::<&Cat>()); println!("{}", std::mem::size_of::<&dyn Pet>()); println!("{}", std::mem::size_of::<Box<dyn Pet>>());