Menu
Coddy logo textTech

שליחה דינמית

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Rust של Coddy. שיעור 45 מתוך 61.

כשמשתמשים בגנריות עם חסמי תכונה כמו <T: Summary>, Rust קובעת את הסוג המדויק בזמן הקומפילציה. זה נקרא שליחה סטטית: המהדר מייצר קוד מותאם לכל סוג קונקרטי שבו משתמשים. זה מהיר, אבל יש מגבלה: משתנה יכול להכיל רק סוג מסוים אחד.

מה אם תצטרכו משתנה יחיד שיוכל להכיל סוגים שונים בזמן ריצה? כאן נכנסים לתמונה אובייקטי תכונה. באמצעות Box<dyn Trait>, תוכלו לאחסן כל סוג שמממש את התכונה:

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 animal: Box<dyn Speak> = Box::new(Dog);
    println!("{}", animal.speak());  // "Woof!"
    
    let animal: Box<dyn Speak> = Box::new(Cat);
    println!("{}", animal.speak());  // "Meow!"
}

מילת המפתח dyn מציינת שליחה דינמית: Rust מחפשת בזמן ריצה איזו מתודה לקרוא, במקום בזמן הידור. ה־Box נחוץ משום שלאובייקטים של תכונה אין גודל ידוע; Box מספק מצביע בגודל קבוע.

חשוב על זה כך: גנריות אומרות "אני עובד עם טיפוס T", בעוד שאובייקטי trait אומרים "אני עובד עם כל דבר שיכול לעשות זאת." הפשרה היא עלות קטנה בזמן הריצה בתמורה לגמישות של טיפול בטיפוסים שונים באמצעות אותו משתנה.

challenge icon

אתגר

קל

בואו נבנה מערכת להשכרת כלי רכב שמדגימה את העוצמה של שליחה דינמית! תיצרו trait שמגדיר מה כל כלי רכב שניתן להשכיר יכול לעשות, ואז תשתמשו ב-Box<dyn Trait> כדי לאחסן סוגים שונים של כלי רכב באותו משתנה.

תארגנו את הקוד שלכם בשני קבצים:

  • vehicle.rs: הגדירו trait ציבורי בשם Rentable עם מתודה בשם rental_info שמקבלת &self ומחזירה String. לאחר מכן צרו שתי struct-ים ציבוריים:
    • Car: עם שדה ציבורי בשם model (String). המתודה rental_info שלה צריכה להחזיר Car: {model}
    • Bike: עם שדה ציבורי בשם brand (String). המתודה rental_info שלה צריכה להחזיר Bike: {brand}
  • main.rs: הכניסו את מודול כלי הרכב והשתמשו בקלטים כדי להדגים שליחה דינמית. צרו משתנה Box<dyn Rentable> שמחזיק תחילה Car, הדפיסו את פרטי ההשכרה שלו, ואז הקצו מחדש לאותו משתנה Bike והדפיסו שוב את פרטי ההשכרה שלו.

הקסם כאן הוא שמשתנה יחיד מסוג Box<dyn Rentable> יכול להחזיק Car או Bike: Rust קובעת איזו מתודת rental_info לקרוא בזמן ריצה. זו שליחה דינמית בפעולה!

הפלט שלכם צריך להציג את המידע של שני כלי הרכב:

Car: {model}
Bike: {brand}

לדוגמה, עם הקלטים Tesla Model 3 ו-Trek:

Car: Tesla Model 3
Bike: Trek

תקבלו שני קלטים: דגם המכונית ומותג האופניים.

נסו בעצמכם

mod vehicle;

use vehicle::{Rentable, Car, Bike};

fn main() {
    // קרא את הקלט
    let mut car_model = String::new();
    std::io::stdin().read_line(&mut car_model).expect("Failed to read line");
    let car_model = car_model.trim().to_string();
    
    let mut bike_brand = String::new();
    std::io::stdin().read_line(&mut bike_brand).expect("Failed to read line");
    let bike_brand = bike_brand.trim().to_string();
    
    // TODO: צור משתנה מסוג Box<dyn Rentable> שמכיל Car
    // הדפס את פרטי ההשכרה שלו באמצעות המתודה rental_info()
    
    // TODO: הקצה מחדש לאותו משתנה ערך שמכיל Bike
    // הדפס שוב את פרטי ההשכרה שלו
    
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Rust אונליין