Menu
Coddy logo textTech

תחביר של אילוצי תכונות

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

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

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

fn print_info<T>(item: T) {
    println!("{}", item.summarize());  // שגיאה! ייתכן של-T אין summarize()
}

הפתרון הוא חסם תכונה. על ידי הוספת : TraitName אחרי הפרמטר הגנרי, אומרים ל-Rust ש-T חייב לממש את התכונה הזו:

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

fn print_info<T: Summary>(item: T) {
    println!("{}", item.summarize());  // כעת Rust יודעת שהמתודה הזו קיימת
}

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

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

challenge icon

אתגר

קל

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

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

  • notification.rs: הגדירו תכונה ציבורית Notify עם מתודה בשם message שמקבלת &self ומחזירה String. לאחר מכן צרו שתי מחלקות מבנה ציבוריות שמממשות את התכונה הזאת:
    • Email: עם שדה ציבורי subject (String). המתודה message שלה צריכה להחזיר Email: {subject}
    • SMS: עם שדה ציבורי content (String). המתודה message שלה צריכה להחזיר SMS: {content}
    לבסוף, צרו פונקציה גנרית ציבורית בשם send_notification שמקבלת כל טיפוס T המממש את התכונה Notify. הפונקציה הזאת צריכה להדפיס את התוצאה של קריאה ל-message() על הפריט.
  • main.rs: כללו את מודול ההתראות שלכם והשתמשו בקלטים שסופקו כדי ליצור מופע של Email וגם מופע של SMS. קראו ל-send_notification עם כל אחד מהם כדי להדגים שהפונקציה הגנרית שלכם פועלת עם כל טיפוס שמממש את Notify.

התובנה המרכזית כאן היא ש-send_notification לא יודעת מהו הטיפוס הקונקרטי שהיא מקבלת. היא יודעת רק שהטיפוס יכול ליצור הודעה. גבול התכונה T: Notify מבטיח את היכולת הזאת.

הפלט שלכם צריך להציג את שתי ההתראות נשלחות:

Email: {subject}
SMS: {content}

לדוגמה, עם הקלטים Meeting Tomorrow ו-On my way!:

Email: Meeting Tomorrow
SMS: On my way!

תקבלו שני קלטים: נושא האימייל ותוכן הודעת ה-SMS.

נסו בעצמכם

mod notification;

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

fn main() {
    // קרא את הקלטים
    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: צור מופע של Email עם הנושא
    
    // TODO: צור מופע של SMS עם התוכן
    
    // TODO: קרא ל-send_notification עם האימייל
    
    // TODO: קרא ל-send_notification עם ה-sms
}
quiz iconבחנו את עצמכם

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

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

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