Menu
Coddy logo textTech

Trait Vektörleri

Coddy'nin Rust Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 46 / 61.

Box<dyn Trait>'in tek bir değişkenin farklı türleri tutmasına nasıl izin verdiğini gördünüz. Asıl güç, bunu koleksiyonlarla birleştirdiğinizde —tek bir vektörde birden fazla farklı türü depolayarak— ortaya çıkar.

Normal bir vektör, tüm öğelerin aynı türde olmasını gerektirir. Aynı zamanda kedileri de içeren bir Vec<Dog> yapısına sahip olamazsınız. Ancak trait nesneleri ile, paylaşılan bir trait'i uygulayan herhangi bir şeyi tutan bir vektör oluşturabilirsiniz:

trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;
struct Bird;

impl Speak for Dog {
    fn speak(&self) -> String { String::from("Woof!") }
}

impl Speak for Cat {
    fn speak(&self) -> String { String::from("Meow!") }
}

impl Speak for Bird {
    fn speak(&self) -> String { String::from("Tweet!") }
}

fn main() {
    let animals: Vec<Box<dyn Speak>> = vec![
        Box::new(Dog),
        Box::new(Cat),
        Box::new(Bird),
    ];
}

Vec<Box<dyn Speak>> türü, "kutulanmış trait nesnelerinden oluşan bir vektör" anlamına gelir. Her bir öğe, Speak trait'ini uygulayan bir şeye işaret eden bir Box'tır; gerçek türler farklılık gösterebilir. Her bir değeri vektöre eklerken Box::new() ile sarmalarsınız.

Bu desen; UI bileşenleri, oyun varlıkları veya eklenti sistemleri gibi ilişkili ancak farklı nesnelerden oluşan koleksiyonları yönetmeniz gereken esnek sistemler oluşturmak için temeldir.

challenge icon

Görev

Kolay

Farklı türdeki uyarıları işleyebilen bir bildirim sistemi kuralım! Trait nesnelerini kullanarak e-postalar, SMS mesajları ve anlık bildirimler gibi çeşitli bildirim türlerini tek bir vektörde saklayan bir koleksiyon oluşturacaksınız.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • notifications.rs: &self alan ve gönderilen bildirimi açıklayan bir String döndüren send metoduna sahip genel (public) bir Notify trait'i tanımlayın. Ardından üç adet genel struct oluşturun:
    • Email — genel bir recipient alanına (String) sahip. send metodu "Email to: {}" formatında bir değer döndürmelidir.
    • Sms — genel bir phone alanına (String) sahip. send metodu "SMS to: {}" formatında bir değer döndürmelidir.
    • Push — genel bir device alanına (String) sahip. send metodu "Push to: {}" formatında bir değer döndürmelidir.
  • main.rs: Bildirim modülünüzü dahil edin ve her üç bildirim türünü de tutan Vec<Box<dyn Notify>> tipinde bir vektör oluşturun. Her bir bildirim türünden birer tane oluşturmak için sağlanan girdileri kullanın, bunları sırasıyla (Email, Sms, Push) vektörünüze ekleyin ve ardından vektörün ilk elemanı üzerinde send() metodunu çağırmanın sonucunu yazdırın.

Buradaki temel kavram, Email, Sms ve Push tamamen farklı struct'lar olmalarına rağmen, Notify trait'ini paylaştıkları için hepsinin aynı vektörde bir arada bulunabilmesidir. Her eleman, trait nesnesini oluşturmak için Box::new() ile sarmalanır.

Çıktınız ilk bildirimi göstermelidir:

Email to: {recipient}

Örneğin, "alice@example.com", "555-1234" ve "iPhone-12" girdileriyle:

Email to: alice@example.com

Üç girdi alacaksınız: e-posta alıcısı, telefon numarası ve cihaz adı.

Kopya kağıdı

Bir Vec<Box<dyn Trait>>, hepsi aynı trait'i uyguladığı sürece tek bir vektörde birden fazla farklı türün saklanmasına olanak tanır.

Normal vektörler tüm öğelerin aynı türde olmasını gerektirir, ancak trait nesneleri heterojen koleksiyonlara olanak sağlar:

trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;

impl Speak for Dog {
    fn speak(&self) -> String { String::from("Woof!") }
}

impl Speak for Cat {
    fn speak(&self) -> String { String::from("Meow!") }
}

fn main() {
    let animals: Vec<Box<dyn Speak>> = vec![
        Box::new(Dog),
        Box::new(Cat),
    ];
}

Vektöre ekleme yaparken her öğe Box::new() ile sarmalanır. Paylaşılan trait'i uyguladıkları sürece gerçek türler farklılık gösterebilir.

Kendin dene

mod notifications;

use notifications::{Notify, Email, Sms, Push};

fn main() {
    // Girdileri oku
    let mut recipient = String::new();
    std::io::stdin().read_line(&mut recipient).expect("Failed to read line");
    let recipient = recipient.trim().to_string();

    let mut phone = String::new();
    std::io::stdin().read_line(&mut phone).expect("Failed to read line");
    let phone = phone.trim().to_string();

    let mut device = String::new();
    std::io::stdin().read_line(&mut device).expect("Failed to read line");
    let device = device.trim().to_string();

    // TODO: Farklı bildirim türlerini tutmak için bir Vec<Box<dyn Notify>> oluşturun
    // TODO: Girdileri kullanarak Email, Sms ve Push örnekleri oluşturun
    // TODO: Bunları Box::new() kullanarak sırasıyla (Email, Sms, Push) vektöre ekleyin
    // TODO: İlk eleman üzerinde send() metodunu çağırmanın sonucunu yazdırın
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Object Oriented Programming bölümündeki tüm dersler