Trait Objects dyn T
These allow for multiple concrete types to fill in for an object at runtime.
Example below is a user adding UI elements at runtime, we don't know what they'll add at compile time so we keep a Vector, as long as it implements Draw
it can be added to the list. Then we can loop over each item and call draw()
pub struct Screen { pub components: Vec<Box<dyn Draw>>, } pub struct Button { pub width: u32, pub height: u32, pub label: String, } pub trait Draw { fn draw(&self); } impl Draw for Button { fn draw(&self) { println!( "Drawing a Button with width: {} height: {} label: {}", self.width, self.height, self.label ); } } impl Screen { pub fn run(&self) { for component in self.components.iter() { component.draw(); } } } #[derive(Debug)] pub struct SelectBox { pub width: u32, pub height: u32, pub options: Vec<String>, } impl Draw for SelectBox { fn draw(&self) { println!( "Drawing a Button with width: {} height: {} options: {:?}", self.width, self.height, self.options ) } } fn main() { let screen = Screen { components: vec![ Box::new(SelectBox { width: 75, height: 10, options: vec![ String::from("Yes"), String::from("Maybe"), String::from("No"), ], }), Box::new(Button { width: 50, height: 10, label: String::from("Ok"), }), ], }; screen.run(); }
Must be object safe, rules are the all methods must:
- Not return Self.
- Have no generic type parameters.