Objetos de Trait Proprietários
Anteriormente vimos como objetos de trait podem ser usados com referências, por exemplo, &dyn Pet
. No entanto, também podemos usar objetos de trait com ponteiros inteligentes como Box
para criar um objeto de trait owned: Box<dyn Pet>
.
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!("Auau, meu nome é {}", 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("Bidu"), age: 5 }), ]; for pet in pets { println!("Olá, quem é você? {}", pet.talk()); } }
Layout da memória após alocar pets
:
This slide should take about 10 minutes.
- Tipos que implementam um dado
trait
podem ter tamanhos diferentes. Isto torna impossível haver coisas comoVec<dyn Pet>
no exemplo anterior. dyn Pet
é uma maneira de dizer ao compilador sobre um tipo de tamanho dinâmico que implementaPet
.- No exemplo,
pets
é alocado na pilha e os dados do vetor estão no heap. Os dois elementos do vetor são fat pointers (ponteiros “gordos”):- Um fat pointer é um ponteiro de dupla largura. Ele tem dois componentes: um ponteiro para o objeto real e um ponteiro para a tabela de métodos virtuais (vtable) para a implementação
Pet
desse objeto em particular. - Os dados para o
Dog
chamado Fido são os camposname
eage
. OCat
tem um campolives
.
- Um fat pointer é um ponteiro de dupla largura. Ele tem dois componentes: um ponteiro para o objeto real e um ponteiro para a tabela de métodos virtuais (vtable) para a implementação
- 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>>());