特征对象
特征(Trait)对象可接受不同类型的值,举例来说,在集合中会是这样:
1. struct Dog {
2. name: String,
3. age: i8,
4. }
5. struct Cat {
6. lives: i8,
7. }
9. trait Pet {
10. fn talk(&self) -> String;
11. }
13. impl Pet for Dog {
14. fn talk(&self) -> String {
15. format!("Woof, my name is {}!", self.name)
16. }
17. }
19. impl Pet for Cat {
20. fn talk(&self) -> String {
21. String::from("Miau!")
22. }
23. }
25. fn main() {
26. let pets: Vec<Box<dyn Pet>> = vec![
27. Box::new(Cat { lives: 9 }),
28. Box::new(Dog { name: String::from("Fido"), age: 5 }),
29. ];
30. for pet in pets {
31. println!("Hello, who are you? {}", pet.talk());
32. }
33. }
以下是分配 pets 后的内存布局:

This slide should take about 10 minutes.
- 实现给定 trait 的类型可能大小不同。因此,上例中不可能具有像
Vec<dyn Pet>这样的项。 - 可通过“dyn Pet”这个方法向编译器告知实现“Pet”的动态大小类型。
- 在本例中,
pets在栈上分配内存,矢量数据存储在堆上。这两个矢量元素是 胖指针: - 胖指针属于全角指针。它包含两个部分:指向实际对象的指针,以及指向该特定对象的
Pet实现的 虚拟方法表 (vtable) 的指针。 Dog(名为 Fido)类型的数据是name和age字段。Cat类型包含一个lives字段。- 比较上述示例中的这些输出:
1. println!("{} {}", std::mem::size_of::<Dog>(), std::mem::size_of::<Cat>());
2. println!("{} {}", std::mem::size_of::<&Dog>(), std::mem::size_of::<&Cat>());
3. println!("{}", std::mem::size_of::<&dyn Pet>());
4. println!("{}", std::mem::size_of::<Box<dyn Pet>>());
