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
traitpodem 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
Petdesse objeto em particular. - Os dados para o
Dogchamado Fido são os camposnameeage. OCattem 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>>());