Menu
Coddy logo textTech

Trait Sınırlandırıcı Sözdizimi

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

Şu ana kadar, trait'leri tanımlamayı ve onları struct'lar için uygulamayı öğrendiniz. Esnek kod yazmak için generic'lerle de çalıştınız. Şimdi bu kavramları birleştirme zamanı; generic bir fonksiyonun hangi türleri kabul edebileceğini kısıtlamak için trait'leri kullanacağız.

Parametresi üzerinde belirli bir metodu çağırması gereken genel (generic) bir fonksiyonu düşünün. Herhangi bir kısıtlama olmaksızın, Rust'ın T türünün bu metoda sahip olduğuna dair bir garantisi yoktur:

fn print_info<T>(item: T) {
    println!("{}", item.summarize());  // Hata! T, summarize() metoduna sahip olmayabilir
}

Çözüm bir trait bound'dur (trait sınırı). Jenerik parametreden sonra : TraitName ekleyerek, Rust'a T tipinin bu trait'i uygulaması gerektiğini söylersiniz:

trait Summary {
    fn summarize(&self) -> String;
}

fn print_info<T: Summary>(item: T) {
    println!("{}", item.summarize());  // Artık Rust bu metodun var olduğunu biliyor
}

<T: Summary> söz dizimi "T, Summary özelliğini uygulayan herhangi bir türdür" şeklinde okunur. Artık fonksiyon yalnızca gerekli davranışa sahip olan türleri kabul eder. Eğer Summary özelliğini uygulamayan bir tür geçirmeye çalışırsanız, derleyici bunu net bir hata ile reddedecektir.

Bu desen güçlüdür çünkü belirli işlevlere hâlâ erişimi olan generic kodlar yazmanıza olanak tanır. Fonksiyonunuz esnek kalır—herhangi bir tiple çalışır—ancak yalnızca ihtiyacınız olan davranışı sağlayan tiplerle.

challenge icon

Görev

Kolay

Sadece uygun şekilde biçimlendirilmiş mesajların gönderilebilmesini sağlamak için trait bound'ları (trait sınırları) kullanan bir bildirim sistemi oluşturalım! Belirli bir trait'i uygulayan herhangi bir türü kabul eden genel (generic) bir fonksiyon oluşturacak ve trait bound'ların generic parametreleri nasıl kısıtladığını göreceksiniz.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • notification.rs: &self alan ve bir String döndüren message adında bir metoda sahip genel kullanıma açık (public) bir Notify trait'i tanımlayın. Ardından bu trait'i uygulayan iki public struct oluşturun:
    • Email — public bir subject alanına (String) sahip. message metodu Email: {subject} döndürmelidir.
    • SMS — public bir content alanına (String) sahip. message metodu SMS: {content} döndürmelidir.
    Son olarak, Notify trait'ini uygulayan herhangi bir T türünü kabul eden send_notification adında public bir generic fonksiyon oluşturun. Bu fonksiyon, öğe üzerinde message() çağrısının sonucunu yazdırmalıdır.
  • main.rs: Bildirim modülünüzü içeri aktarın ve hem bir Email hem de bir SMS örneği oluşturmak için sağlanan girdileri kullanın. Generic fonksiyonunuzun Notify uygulayan herhangi bir türle çalıştığını kanıtlamak için her biriyle send_notification fonksiyonunu çağırın.

Buradaki temel nokta, send_notification fonksiyonunun aldığı somut türü bilmemesidir; sadece o türün bir mesaj üretebileceğini bilir. T: Notify trait bound'u bu yeteneği garanti eder.

Çıktınız her iki bildirimin de gönderildiğini göstermelidir:

Email: {subject}
SMS: {content}

Örneğin, Meeting Tomorrow ve On my way! girdileriyle:

Email: Meeting Tomorrow
SMS: On my way!

İki girdi alacaksınız: e-posta konusu ve SMS içeriği.

Kopya kağıdı

Bir trait bound, genel bir tür parametresini yalnızca belirli bir trait'i uygulayan türleri kabul edecek şekilde kısıtlar.

Trait bound'lar için sözdizimi, genel parametreden sonra : TraitName kullanır:

fn function_name<T: TraitName>(item: T) {
    // Artık item üzerinde TraitName metodları çağrılabilir
}

Bir trait bound örneği:

trait Summary {
    fn summarize(&self) -> String;
}

fn print_info<T: Summary>(item: T) {
    println!("{}", item.summarize());
}

<T: Summary> gösterimi, "T, Summary trait'ini uygulayan herhangi bir türdür" anlamına gelir. Bu, fonksiyonun genel (generic) kalırken trait metodlarını çağırmasına olanak tanır.

Kendin dene

mod notification;

use notification::{Email, SMS, send_notification};

fn main() {
    // Girdileri oku
    let mut subject = String::new();
    std::io::stdin().read_line(&mut subject).expect("Failed to read line");
    let subject = subject.trim().to_string();
    
    let mut content = String::new();
    std::io::stdin().read_line(&mut content).expect("Failed to read line");
    let content = content.trim().to_string();
    
    // TODO: Konu ile bir Email örneği oluşturun
    
    // TODO: İçerik ile bir SMS örneği oluşturun
    
    // TODO: Email ile send_notification fonksiyonunu çağırın
    
    // TODO: SMS ile send_notification fonksiyonunu çağı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