Objetos Trait
Objetos trait
permitem valores de diferentes tipos, por exemplo, em uma coleção:
trait Pet { fn name(&self) -> String; } struct Dog { name: String, } struct Cat; impl Pet for Dog { fn name(&self) -> String { self.name.clone() } } impl Pet for Cat { fn name(&self) -> String { String::from("Gato") // Sem nomes, gatos não respondem mesmo. } } fn main() { let pets: Vec<Box<dyn Pet>> = vec![ Box::new(Cat), Box::new(Dog { name: String::from("Bidu") }), ]; for pet in pets { println!("Olá {}!", pet.name()); } }
Layout da memória após alocar pets
:
- Tipos que implementam um dado
trait
podem ter tamanhos diferentes. Isto torna impossível haver coisas comoVec<Pet>
no exemplo anterior. dyn Pet
é uma maneira de dizer ao compilador sobre um tipo de tamanho dinâmico que implementaPet
.- No exemplo,
pets
possui fat pointers para objetos que implementamPet
. O fat pointer consiste em dois componentes, um ponteiro para o objeto propriamente dito e um ponteiro para a tabela de métodos virtuais para a implementação dePet
do objeto em particular. - Compare estas saídas no exemplo anterior::
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>>());