פונקציות גנריות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Rust של Coddy. שיעור 27 מתוך 61.
Generics אינם מוגבלים למבנים. אפשר גם לכתוב פונקציות עצמאיות שעובדות עם כל סוג. זה שימושי כשצריך פונקציית עזר שלא שייכת למבנה מסוים, אבל עדיין צריכה להיות גמישה.
התחביר דומה לזה שראית עם מבנים. הכריזו על הפרמטר הגנרי בתוך סוגריים זוויתיים אחרי שם הפונקציה, ואז השתמשו בו בפרמטרים ובטיפוס ההחזרה:
fn identity<T>(value: T) -> T {
value
}
הפונקציה identity מקבלת ערך מכל סוג שהוא ומחזירה אותו ללא שינוי. <T> מצהיר על הטיפוס הגנרי, value: T מקבל אותו כפרמטר, ו־-> T מציין את טיפוס ההחזרה. כשקוראים לפונקציה, Rust מסיק את הטיפוס הקונקרטי:
let num = identity(42); // T הוא i32
let text = identity("hello"); // T הוא &str
אפשר גם להשתמש בכמה פרמטרים גנריים בפונקציות, בדיוק כמו במבנים:
fn make_pair<T, U>(first: T, second: U) -> (T, U) {
(first, second)
}
let pair = make_pair(10, "ten"); // מחזירה (i32, &str)
פונקציות גנריות מאפשרות לך לכתוב לוגיקה רב־פעמית פעם אחת ולהחיל אותה על טיפוסים רבים, תוך צמצום שכפול הקוד ושמירה על בטיחות הטיפוסים.
אתגר
קלבואו נבנה מודול עזר עם פונקציות גנריות שיכולות לעבוד עם כל טיפוס! תיצרו פונקציות עצמאיות שמדגימות איך גנריות הופכות את הקוד שלכם לגמיש ולשימוש חוזר, בלי לקשור אותו למבנה נתונים מסוים.
תארגנו את הקוד שלכם בשני קבצים:
utils.rs: צרו אוסף של פונקציות עזר גנריות ציבוריות:wrap_in_pair<T>: מקבלת ערך יחיד ומחזירה זוג (tuple) שמכיל את אותו ערך פעמיים:(value, value). לשם כך הטיפוס חייב לממש אתClone, לכן השתמשו ב-<T: Clone>swap<T, U>: מקבלת שני ערכים שעשויים להיות מטיפוסים שונים ומחזירה אותם בסדר הפוך כזוג(U, T)
main.rs: ייבאו את מודול העזר שלכם והדגימו את הפונקציות הגנריות האלה בעבודה עם טיפוסים שונים. הראו איך אותן הגדרות של פונקציות מטפלות במספרים שלמים, במספרים ממשיים ובמחרוזות בצורה חלקה.
בקובץ הראשי שלכם, הדגימו את פונקציות העזר שלכם כך:
- השתמשו ב-
wrap_in_pairעם מספר שלם (הקלט הראשון, שמנותח כ-i32) והדפיסו את שני האיברים - השתמשו ב-
wrap_in_pairעם מחרוזת (הקלט השני) והדפיסו את שני האיברים - השתמשו ב-
swapעם מספר שלם (הקלט השלישי, שמנותח כ-i32) ומחרוזת (הקלט הרביעי), ואז הדפיסו את התוצאה לאחר החלפת הסדר
הפלט שלכם צריך להיות בפורמט הזה:
Pair of ints: ({value}, {value})
Pair of strings: ({value}, {value})
Swapped: ({string}, {int})לדוגמה, עבור הקלטים 5, hello, 42 ו-world:
Pair of ints: (5, 5)
Pair of strings: (hello, hello)
Swapped: (world, 42)שימו לב איך wrap_in_pair פועלת באופן זהה גם עם מספרים שלמים וגם עם מחרוזות, ו-swap מטפלת בשני טיפוסים שונים לחלוטין: זו הגמישות של פונקציות גנריות!
תקבלו ארבעה קלטים: מספר שלם, מחרוזת, מספר שלם נוסף ומחרוזת נוספת.
נסו בעצמכם
mod utils;
use std::io;
fn main() {
// קראו את ארבעת הקלטים
let mut input1 = String::new();
io::stdin().read_line(&mut input1).expect("Failed to read line");
let num1: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
io::stdin().read_line(&mut input2).expect("Failed to read line");
let str1 = input2.trim().to_string();
let mut input3 = String::new();
io::stdin().read_line(&mut input3).expect("Failed to read line");
let num2: i32 = input3.trim().parse().expect("Invalid integer");
let mut input4 = String::new();
io::stdin().read_line(&mut input4).expect("Failed to read line");
let str2 = input4.trim().to_string();
// TODO: השתמשו ב-wrap_in_pair עם num1 והדפיסו את התוצאה
// פורמט: Pair of ints: ({value}, {value})
// TODO: השתמשו ב-wrap_in_pair עם str1 והדפיסו את התוצאה
// פורמט: Pair of strings: ({value}, {value})
// TODO: השתמשו ב-swap עם num2 ו-str2, ואז הדפיסו את התוצאה לאחר ההחלפה
// פורמט: Swapped: ({string}, {int})
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1מתודות והתנהגות
מבוא לבלוקי מימושהפרמטר selfמתודות ניתנות לשינויפונקציות משויכותבלוקי מימוש מרוביםשרשור מתודותסיכום – פעולות מלבן4פרויקט: חיית מחמד וירטואלית
הגדרת חיית המחמדהאכלת חיית המחמדתרגלו בעצמכם: קומפיילר Rust אונליין