תחביר של אילוצי תכונות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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, המהדר ידחה אותו ויציג שגיאה ברורה.
התבנית הזו עוצמתית כי היא מאפשרת לך לכתוב קוד גנרי שעדיין יש לו גישה לפונקציונליות ספציפית. הפונקציה שלך נשארת גמישה ועובדת עם כל טיפוס, אבל רק עם טיפוסים שמספקים את ההתנהגות הדרושה לך.
אתגר
קלבואו נבנה מערכת התראות שמשתמשת בגבולות תכונות כדי להבטיח שניתן לשלוח רק הודעות בפורמט מתאים! תיצרו פונקציה גנרית שמקבלת כל טיפוס המממש תכונה מסוימת, וכך תדגימו כיצד גבולות תכונות מגבילים פרמטרים גנריים.
תארגנו את הקוד בשני קבצים:
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
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1מתודות והתנהגות
מבוא לבלוקי מימושהפרמטר selfמתודות ניתנות לשינויפונקציות משויכותבלוקי מימוש מרוביםשרשור מתודותסיכום – פעולות מלבן4פרויקט: חיית מחמד וירטואלית
הגדרת חיית המחמדהאכלת חיית המחמד8תכונות כאילוצים
תחביר של אילוצי תכונותאילוצים מרוביםסעיף whereהחזרת טיפוסים עם תכונותסיכום - מדפיס גנריתרגלו בעצמכם: קומפיילר Rust אונליין