Sahipli Özellik Nesneleri (Owned Trait Objects)

Daha önce özellik nesnelerinin (trait objects) referanslarla nasıl kullanılabileceğini görmüştük, örn. &dyn Pet. Ancak, sahip olunan (owned) bir özellik nesnesi oluşturmak için Box gibi akıllı göstericilerle de özellik nesnelerini kullanabiliriz: 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!("Hav, benim adım {}!", self.name)
    }
}

impl Pet for Cat {
    fn talk(&self) -> String {
        String::from("Miyav!")
    }
}

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!("Merhaba, nasılsın? {}", pet.talk());
    }
}

pets tahsis edildikten sonraki bellek düzeni:

<Dog as Pet>::talk<Cat as Pet>::talkStackHeapFidoptrlives9len2capacity2data:name,4,4age5vtablevtablepets: Vec<Box<dyn Pet>>data: CatDogProgram text
This slide should take about 10 minutes.
  • Belirli bir özelliği (trait) gerçekleştiren türler farklı boyutlarda olabilir. Bu, yukarıdaki örnekte Vec<dyn Pet> gibi şeylere sahip olmayı imkansız kılar.
  • dyn Pet, derleyiciye Pet’i gerçekleştiren dinamik boyutlu bir tür hakkında bilgi vermenin bir yoludur.
  • Örnekte, pets yığın (stack) üzerinde tahsis edilir ve vektör verisi dinamik bellektedir (heap). İki vektör elemanı genişletilmiş göstericilerdir (fat pointers):
    • Genişletilmiş bir gösterici (fat pointer), çift genişlikli bir göstericidir. İki bileşeni vardır: gerçek nesneye bir gösterici ve o belirli nesnenin Pet gerçekleştirmesi için sanal metot tablosuna (virtual method table) (vtable) bir gösterici.
    • Fido adındaki Dog için veri, name ve age alanlarıdır. Cat’in bir lives alanı vardır.
  • Yukarıdaki örnekte bu çıktıları karşılaştırın:
    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>>());