Generics

  • Rust übernimmt für Generics ähnliche Konstrukte wie bei C++ oder Java
  • Auch hier spielt die Typeninferenz wieder eine Rolle, da die konkreten Typen aus dem Zusammenhang geschlußfolgert werden können
  • Konkrete müssen nicht zur Laufzeit instanziiert und dann konvertiert werden
struct MyGenericStruct<T> {
    items: Vec<T>,
}

fn main() {
    let struct_with_u32: MyGenericStruct<u32> = MyGenericStruct {
        items: vec![],
    };

    let struct_with_u16 = MyGenericStruct::<u16> {
        items: Vec::new()
    };

    let struct_with_u8 = MyGenericStruct {
        items: Vec::<u8>::new()
    };
}
  • Generische Typen können konkrete Implementierungen nur für einen Typ besitzen
struct MyGenericStruct<T> {
    a: T,
    b: T,
}

impl MyGenericStruct<i32> {
    fn sum(&self) -> i32 {
        self.a + self.b
    }
}

fn main() {
    // Für i32 liegt eine Implementierung vor, u32 Typen können nicht verarbeitet werden
    MyGenericStruct { a: 1, b: 2 }.sum();
}
  • Auch für generische Typen können generische Implementierungen verwendet werden
  • Damit er Kompiler dies richtig umsetzen kann, müssen wir ggf. Randbedingungen an unsere Generics stellen, welche Traits umgesetzt werden müssen
struct MyGenericStruct<T> {
    a: T,
    b: T,
}

impl<T> MyGenericStruct<T> where T: std::ops::Add<Output=T>, T: std::marker::Copy {
    fn sum(&self) -> T {
        self.a + self.b
    }
}

fn main() {
    MyGenericStruct { a: 1i32, b: 2i32 }.sum();
    MyGenericStruct { a: 3u32, b: 4u32 }.sum();
    MyGenericStruct { a: 5i8, b: 6i8 }.sum();
    MyGenericStruct { a: 7.1, b: 8.2 }.sum();
}