特徵物件
特徵物件可接受不同型別的值,舉例來說,在集合中會是這樣:
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("The cat") // No name, cats won't respond to it anyway. } } fn main() { let pets: Vec<Box<dyn Pet>> = vec![ Box::new(Cat), Box::new(Dog { name: String::from("Fido") }), ]; for pet in pets { println!("Hello {}!", pet.name()); } }
以下是配置 pets
後的記憶體配置:
- 如果型別會實作特定特徵,大小可能會不同。因此在上例中就不可能出現
Vec<Pet>
這類項目。 - 可透過
dyn Pet
這個方法向編譯器告知實作Pet
的動態大小型別。 - 在本例中,
pets
會保留指向物件的「虛指標」__,而物件會實作Pet
。虛指標包含兩個元件,指向實際物件的指標,以及指向該特定物件中Pet
實作項目的虛擬方法表格。 - 比較上述範例的輸出內容:
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>>());