Zum Inhalt springen

Generics

Stellen Sie sich vor, Sie verwenden eine Drittanbieterfunktion, deren Implementierung Sie nicht kennen, deren Typsignatur jedoch wie folgt aussieht:

fn mystery<T>(x: T) -> T {
// ????
}

Dann rufen Sie mystery wie folgt auf:

let y = mystery(3);

Angenommen, mystery verwendet keinen unsicheren Code, dann muss der Wert von y sein:

Die einzige mögliche Funktion (ohne unsicheren Code), die die Signatur T -> T hat, ist die Identitätsfunktion:

fn mystery<T>(x: T) -> T {
x
}

Die Funktion könnte natürlich paniken oder etwas ausgeben, aber der Rückgabewert kann nur der Eingabewert sein. mystery weiß nicht, welchen Typ T hat, daher gibt es für mystery keine Möglichkeit, einen Wert vom Typ T zu generieren oder zu mutieren. Weitere Beispiele für diese Idee finden Sie unter Theorems for free!.


fn print_slice<T>(v: &[T]) {
for x in v {
println!("{x}");
}
}
fn main() {
print_slice(&[1, 2, 3]);
}

Wenn ein Typ generisch ist (wie T), können wir nichts über ihn annehmen, einschließlich der Fähigkeit, ihn in einen String umzuwandeln. Daher ist println!("{x}") ungültig, da x: &T ist.


struct Point<T> { x: T, y: T }
impl Point<i32> {
fn f(&self) -> &i32 { &self.y }
}
impl<T> Point<T> {
fn f(&self) -> &T { &self.x }
}
fn main() {
let p: Point<i32> = Point { x: 1, y: 2 };
println!("{}", p.f());
}

Diese Definitionen von f kollidieren, und Rust kann nicht bestimmen, welche f verwendet werden soll, wenn p.f() aufgerufen wird. Daher handelt es sich um einen Kompilierungsfehler.