dyn Trait

Rust, genelleştirmeler (generics) yoluyla statik yönlendirme (static dispatch) için özellikleri (trait) kullanmaya ek olarak, özellik nesneleri (trait objects) yoluyla silinmiş türle (type-erased), dinamik yönlendirmeyi (dynamic dispatch) destekler:

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!")
    }
}

// Genelleştirmeleri (generics) ve statik yönlendirmeyi (static dispatch) kullanır.
fn generic(pet: &impl Pet) {
    println!("Merhaba, nasılsın? {}", pet.talk());
}

// Tür silmeyi (type-erasure) ve dinamik yönlendirmeyi (dynamic dispatch) kullanır.
fn dynamic(pet: &dyn Pet) {
    println!("Merhaba, nasılsın? {}", pet.talk());
}

fn main() {
    let cat = Cat { lives: 9 };
    let dog = Dog { name: String::from("Fido"), age: 5 };

    generic(&cat);
    generic(&dog);

    dynamic(&cat);
    dynamic(&dog);
}
This slide should take about 5 minutes.
  • impl Trait de dahil olmak üzere genelleştirmeler (generics), genelleştirmenin oluşturulduğu her farklı tür için fonksiyonun özel bir örneğini oluşturmak üzere tek biçimli hâle getirmeyi (monomorphization) kullanır. Bu, genelleştirilmiş bir fonksiyon içinden bir özellik (trait) metodunu çağırmanın hala statik yönlendirme (static dispatch) kullandığı anlamına gelir, çünkü derleyici tam tür bilgisine sahiptir ve hangi türün özellik gerçekleştiriminin (trait implementation) kullanılacağını çözebilir.

  • dyn Trait kullanırken, bunun yerine bir sanal metot tablosu (virtual method table) (vtable) aracılığıyla dinamik yönlendirme (dynamic dispatch) kullanır. Bu, hangi türde Pet geçirilirse geçirilsin kullanılan tek bir fn dynamic sürümü olduğu anlamına gelir.

  • dyn Trait kullanırken, özellik nesnesinin (trait object) bir tür dolaylı yol (indirection) arkasında olması gerekir. Bu durumda bu bir referanstır, ancak Box gibi akıllı gösterici (smart pointer) türleri de kullanılabilir (bu 3. günde gösterilecektir).

  • Çalışma zamanında, bir &dyn Pet, “genişletilmiş bir gösterici (fat pointer)” olarak temsil edilir, yani iki göstericiden oluşan bir çift: Bir gösterici, Pet’i gerçekleştiren (implement) belirli nesneye işaret eder ve diğeri o tür için özellik gerçekleştiriminin (trait implementation) sanal metot tablosuna (vtable) işaret eder. &dyn Pet üzerinde talk metodunu çağırırken, derleyici sanal metot tablosunda talk için fonksiyon göstericisini (function pointer) arar ve ardından Dog veya Cat’e göstericiyi o fonksiyona geçirerek fonksiyonu çağırır. Derleyicinin bunu yapmak için Pet’in belirli olan türünü (concrete type) bilmesi gerekmez.

  • Bir dyn Trait, “silinmiş tür (type-erased)” olarak kabul edilir, çünkü artık somut türün ne olduğuna dair derleme zamanı bilgisine sahip değiliz.