Trait Nesneleri Üzerinde Yineleme
Coddy'nin Rust Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 47 / 61.
Artık farklı türleri bir Vec<Box<dyn Trait>> içinde saklayabildiğinize göre, bir sonraki adım bu koleksiyonu işlemektir. Trait nesneleri üzerinde yineleme yapmak, herhangi bir vektör üzerinde yineleme yapmakla aynı şekilde çalışır—her bir öğe üzerinde döngü kurar ve trait tarafından tanımlanan metotları çağırırsınız.
trait Shape {
fn area(&self) -> f64;
}
struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
impl Shape for Circle {
fn area(&self) -> f64 { 3.14159 * self.radius * self.radius }
}
impl Shape for Rectangle {
fn area(&self) -> f64 { self.width * self.height }
}
fn main() {
let shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 2.0 }),
Box::new(Rectangle { width: 3.0, height: 4.0 }),
Box::new(Circle { radius: 1.0 }),
];
for shape in &shapes {
println!("Area: {}", shape.area());
}
}
for shape in &shapes ile döngü kurduğunuzda, her bir shape bir Box<dyn Shape> referansıdır. Shape trait'inden herhangi bir metodu doğrudan çağırabilirsiniz; Rust dinamik sevki (dynamic dispatch) otomatik olarak yöneterek her somut tür için doğru uygulamayı çağırır.
Bu desen, sonuçları toplamak için güçlüdür. Tüm alanları toplayabilir, şekilleri boyutlarına göre filtreleyebilir veya koleksiyonu dönüştürebilirsiniz. Temel içgörü şudur: Öğeler bir trait nesnesi koleksiyonuna girdikten sonra, temel türlerinden bağımsız olarak onlarla tamamen trait'in arayüzü üzerinden etkileşime girersiniz.
Görev
KolayFarklı türde öğeleri tutabilen bir alışveriş sepeti için bir fiyat hesaplayıcı oluşturalım! Ürünlerin ve hizmetlerin—her biri farklı fiyatlandırma mantığına sahip—birlikte saklanabileceği ve toplam fiyatı hesaplamak için işlenebileceği bir sistem oluşturacaksınız.
Kodunuzu iki dosya halinde düzenleyeceksiniz:
items.rs:&selfalan ve birf64döndüren birpricemetoduna sahip genel birPriceabletrait'i tanımlayın. Ardından iki genel struct oluşturun:Product— genelname(String) vecost(f64) alanlarına sahip.pricemetodu sadececostdeğerini döndürmelidir.Service— genelname(String),hourly_rate(f64) vehours(f64) alanlarına sahip.pricemetoduhourly_rate * hoursdeğerini döndürmelidir.
main.rs: items modülünüzü dahil edin veVec<Box<dyn Priceable>>türünde bir vektör oluşturun. Girdileri kullanarak bir Product ve bir Service oluşturun, bunları vektörünüze ekleyin, ardından tüm öğelerin toplam fiyatını hesaplamak ve yazdırmak için koleksiyon üzerinde döngü kurun.
Trait nesnelerinin gücü burada parlıyor—döngü kodunuzun bir Product mı yoksa bir Service mi işlediğini bilmesine gerek yoktur. Sadece her öğe üzerinde price() metodunu çağırır ve Rust otomatik olarak doğru uygulamaya yönlendirir.
Çıktınız toplam fiyatı bir ondalık basamakla göstermelidir:
Total: ${total}Örneğin, Laptop, 999.99, Consulting, 150.0 ve 3.0 girdileriyle:
Total: $1449.99Ve Book, 29.99, Tutoring, 50.0 ve 2.0 girdileriyle:
Total: $129.99Beş girdi alacaksınız: ürün adı, ürün maliyeti, hizmet adı, saatlik ücret ve çalışılan saat (sayısal değerleri f64 olarak ayrıştırın).
Kopya kağıdı
Bir trait nesneleri koleksiyonu üzerinde yineleme yapmak için, vektöre bir referansla birlikte standart bir for döngüsü kullanın:
for item in &collection {
item.trait_method();
}
for item in &vec ile yineleme yaparken, her bir item bir Box<dyn Trait> referansıdır. Trait içindeki herhangi bir metodu doğrudan çağırabilirsiniz; Rust, dinamik sevki (dynamic dispatch) otomatik olarak yönetir ve her somut tür için doğru uygulamayı çağırır.
Sonuçları bir araya getirmek için trait nesneleri üzerinde yineleme örneği:
trait Shape {
fn area(&self) -> f64;
}
struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
impl Shape for Circle {
fn area(&self) -> f64 { 3.14159 * self.radius * self.radius }
}
impl Shape for Rectangle {
fn area(&self) -> f64 { self.width * self.height }
}
fn main() {
let shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 2.0 }),
Box::new(Rectangle { width: 3.0, height: 4.0 }),
];
for shape in &shapes {
println!("Area: {}", shape.area());
}
}
Bu desen, sonuçları bir araya getirmek için kullanışlıdır; değerleri toplayabilir, kriterlere göre filtreleyebilir veya öğelerle tamamen trait arayüzü üzerinden etkileşime girerken koleksiyonu dönüştürebilirsiniz.
Kendin dene
mod items;
use items::{Priceable, Product, Service};
fn main() {
// Girdileri oku
let mut product_name = String::new();
std::io::stdin().read_line(&mut product_name).expect("Failed to read line");
let product_name = product_name.trim().to_string();
let mut product_cost = String::new();
std::io::stdin().read_line(&mut product_cost).expect("Failed to read line");
let product_cost: f64 = product_cost.trim().parse().expect("Failed to parse");
let mut service_name = String::new();
std::io::stdin().read_line(&mut service_name).expect("Failed to read line");
let service_name = service_name.trim().to_string();
let mut hourly_rate = String::new();
std::io::stdin().read_line(&mut hourly_rate).expect("Failed to read line");
let hourly_rate: f64 = hourly_rate.trim().parse().expect("Failed to parse");
let mut hours = String::new();
std::io::stdin().read_line(&mut hours).expect("Failed to read line");
let hours: f64 = hours.trim().parse().expect("Failed to parse");
// YAPILACAK: product_name ve product_cost kullanarak bir Product oluşturun
// YAPILACAK: service_name, hourly_rate ve hours kullanarak bir Service oluşturun
// YAPILACAK: Bir Vec<Box<dyn Priceable>> oluşturun ve her iki öğeyi de buna ekleyin
// YAPILACAK: Vektör üzerinde döngü kurun ve toplam fiyatı hesaplayın
// YAPILACAK: Toplamı bir ondalık basamakla yazdırın
// Format: Toplam: ${total:.1}
}
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 Player9Trait Nesneleri
Dinamik GönderimTrait VektörleriTrait Nesneleri Üzerinde YinelemeÖzet - Hayvanat Bahçesi Yöneticisi