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.
Görev
KolaySadece 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:&selfalan ve birStringdöndürenmessageadında bir metoda sahip genel kullanıma açık (public) birNotifytrait'i tanımlayın. Ardından bu trait'i uygulayan iki public struct oluşturun:Email— public birsubjectalanına (String) sahip.messagemetoduEmail: {subject}döndürmelidir.SMS— public bircontentalanına (String) sahip.messagemetoduSMS: {content}döndürmelidir.
Notifytrait'ini uygulayan herhangi birTtürünü kabul edensend_notificationadında public bir generic fonksiyon oluşturun. Bu fonksiyon, öğe üzerindemessage()çağrısının sonucunu yazdırmalıdır.main.rs: Bildirim modülünüzü içeri aktarın ve hem birEmailhem de birSMSörneği oluşturmak için sağlanan girdileri kullanın. Generic fonksiyonunuzunNotifyuygulayan herhangi bir türle çalıştığını kanıtlamak için her biriylesend_notificationfonksiyonunu ç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
}
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
1Metotlar ve Davranış
Uygulama Bloklarına GirişSelf ParametresiDeğiştirilebilir Metotlarİlişkili FonksiyonlarBirden Fazla Uygulama BloğuMetot ZincirlemeÖzet - Dikdörtgen Eylemleri4Proje: Sanal Evcil Hayvan
Evcil Hayvanı TanımlamaEvcil Hayvanı Besleme2Kapsülleme ve Modüller
Modül TemelleriPublic Anahtar KelimesiPrivate AlanlarGetter'larSetter'larÖzet - Güvenli Kasa5Generic Yapılar
Generic Struct'larGeneric MetotlarÇoklu Generic TürlerGeneric FonksiyonlarÖzet - Koordinat Noktası8Sınırlandırıcı Olarak Trait'ler
Trait Sınırlandırıcı SözdizimiÇoklu SınırlandırıcılarWhere CümleciğiTrait'ler ile Tip DöndürmeÖzet - Generic Yazıcı11Rust'ta Tasarım Kalıpları
Newtype KalıbıKompozisyonDrop Trait'iFrom ve IntoÖzet - Smart Pointer Mock3İleri Seviye Enum'lar
Veri İçeren Enum'larEnum MetotlarıVeri Varyantlarını EşlemeOption Enum'ına Yeniden BakışÖzet - Shape Enum6Trait Tanımlama
Trait Nedir?Traitleri UygulamaVarsayılan UygulamalarVarsayılanları Geçersiz KılmaParametreli TraitlerÖzet - Media Player