特徵物件

特徵物件可接受不同型別的值,舉例來說,在集合中會是這樣:

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 後的記憶體配置:

name:Fido<Dog as Pet>::name<Cat as Pet>::nameStackHeappetsptrlen2capacity2
  • 如果型別會實作特定特徵,大小可能會不同。因此在上例中就不可能出現 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>>());