לדלג לתוכן

2.2 - פולימורפיזם סטטי ודינמי והקוד שנוצר - פתרון

פתרון מחיקת טיפוס בגבול מוגדר

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

trait Metric {
    fn value(&self) -> u64;
    fn echo<T>(&self, value: T) -> T where Self: Sized { value }
}
struct Constant(u64);
struct Length(String);
impl Metric for Constant { fn value(&self) -> u64 { self.0 } }
impl Metric for Length { fn value(&self) -> u64 { self.0.len() as u64 } }

fn static_sum<T: Metric>(items: &[T]) -> u64 {
    items.iter().map(Metric::value).sum()
}

fn main() {
    let items: Vec<Box<dyn Metric>> = vec![
        Box::new(Constant(5)),
        Box::new(Length("hello".into())),
    ];
    assert_eq!(items.iter().map(|item| item.value()).sum::<u64>(), 10);
    assert_eq!(static_sum(&[Constant(2), Constant(3)]), 5);
    assert_eq!(Constant(1).echo("ok"), "ok");
}

המתודה echo אינה ניתנת לקריאה דרך dyn Metric משום שהיא דורשת Self בגודל ידוע. היא עדיין זמינה עבור Constant קונקרטי. המערך הגנרי אינו יכול להכיל שני טיפוסי איבר שונים; אפשר לאחד אותם באמצעות enum או לבחור במחיקת הטיפוס כפי שעשינו כאן.

ההמרה של אורך ל־u64 מתאימה ליעדי הקורס x86-64 ו־AArch64. בממשק שמבקש ניידות רחבה יותר נכתוב המרה בדוקה ונחליט כיצד לדווח על אורך שאינו ניתן לייצוג.