Objetos Trait Poseídos
Previamente vimos que objetos de trait se pueden usar con referencias, e.g. &dyn Pet. También podemos usar objetos de trait con punteros inteligentes como Box para crear objetos de trait con dueño: 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!("¡Guau, me llamo {}!", 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!("Hola, quien eres? {}", pet.talk());
}
}
Diseño de la memoria después de asignar pets:
This slide should take about 10 minutes.
- Los tipos que implementan un trait pueden tener diferentes tamaños. Esto hace imposible tener elementos como
Vec<dyn Pet>en el ejemplo anterior. dyn Petes una forma de indicar al compilador un tipo de tamaño dinámico que implementaPet.- En este ejemplo,
petses alocado sobre el stack y los datos del vector sobre el heap. Los dos elementos del vector son punteros gordos:- Un puntero gordo es un puntero de tamaño doble. Tiene dos componentes: un puntero al objeto y un puntero a la tabla virtual de métodos (vtable) para la implementación de
Petde ese objeto. - Los datos para el
Dogllamado Fido son los camposnameyage. ElCattiene un campolives.
- Un puntero gordo es un puntero de tamaño doble. Tiene dos componentes: un puntero al objeto y un puntero a la tabla virtual de métodos (vtable) para la implementación de
- Compara estas salidas en el ejemplo 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>>());