Menu
Coddy logo textTech

פונקציות גנריות

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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)

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

challenge icon

אתגר

קל

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

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

  • utils.rs: צרו אוסף של פונקציות כלי עזר גנריות ציבוריות:
    • wrap_in_pair<T>: מקבלת ערך יחיד ומחזירה tuple שמכיל את הערך הזה פעמיים: (value, value). הטיפוס חייב לממש את Clone, לכן השתמשו ב-<T: Clone>
    • swap<T, U>: מקבלת שני ערכים שעשויים להיות מטיפוסים שונים ומחזירה אותם בסדר הפוך כ-tuple מסוג (U, T)
  • main.rs: ייבאו את מודול כלי העזר והדגימו את פעולת הפונקציות הגנריות האלה עם טיפוסים שונים. הראו איך אותן הגדרות של פונקציות מטפלות במספרים שלמים, במספרים עשרוניים ובמחרוזות ללא קושי.

בקובץ הראשי, הדגימו את פונקציות כלי העזר שלכם כך:

  1. השתמשו ב-wrap_in_pair עם מספר שלם (הקלט הראשון, שמפורש כ-i32) והדפיסו את שני האיברים
  2. השתמשו ב-wrap_in_pair עם מחרוזת (הקלט השני) והדפיסו את שני האיברים
  3. השתמשו ב-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})
}
quiz iconבחנו את עצמכם

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

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

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