Einführung
In diesem Lab werden wir das Thema Generics erkunden, das das Verallgemeinern von Typen und Funktionalitäten umfasst, um eine größere Bandbreite von Fällen zu behandeln und die Code-Duplizierung zu reduzieren. Die Syntax für Generics in Rust besteht darin, Typ-Parameter mit spitzen Klammern anzugeben, wie <T>. Mit Hilfe von Generics können wir generische Funktionen erstellen, die Argumente beliebigen Typs akzeptieren. Darüber hinaus können wir generische Typen definieren, die mit verschiedenen konkreten Typen zusammenarbeiten können.
Hinweis: Wenn im Lab kein Dateiname angegeben ist, können Sie einen beliebigen Dateinamen verwenden. Beispielsweise können Sie
main.rsverwenden und es mitrustc main.rs &&./mainkompilieren und ausführen.
Generics
Generics ist das Thema der Verallgemeinerung von Typen und Funktionalitäten auf breitere Fälle. Dies ist extrem nützlich, um Code-Duplizierung auf vielen Wegen zu reduzieren, erfordert jedoch oft eine ziemlich komplexe Syntax. Namentlich erfordert es, bei der Definition von generischen Typen mit größter Sorgfalt festzulegen, über welche Typen ein generischer Typ tatsächlich als gültig angesehen wird. Die einfachste und am häufigsten verwendete Verwendung von Generics sind Typ-Parameter.
Ein Typ-Parameter wird als generisch durch die Verwendung von spitzen Klammern und Großbuchstaben angegeben, typischerweise als <T>. In Rust beschreibt "generisch" auch alles, was einen oder mehrere generische Typ-Parameter <T> akzeptiert. Jeder Typ, der als generischer Typ-Parameter angegeben ist, ist generisch, und alles andere ist konkret (nicht-generisch).
Beispielsweise definieren wir eine generische Funktion namens foo, die ein Argument T beliebigen Typs annimmt:
fn foo<T>(arg: T) {... }
Da T als generischer Typ-Parameter mit <T> angegeben wurde, wird es hier als (arg: T) verwendet als generisch betrachtet. Dies ist auch dann der Fall, wenn T zuvor als struct definiert wurde.
Dieses Beispiel zeigt einige der Syntax in Aktion:
// Ein konkreter Typ `A`.
struct A;
// Beim Definieren des Typs `Single` wird der erste Gebrauch von `A` nicht durch `<A>` vorangestellt.
// Daher ist `Single` ein konkreter Typ, und `A` ist wie oben definiert.
struct Single(A);
// ^ Hier ist der erste Gebrauch von `Single` des Typs `A`.
// Hier wird `<T>` vor dem ersten Gebrauch von `T` eingesetzt, daher ist `SingleGen` ein generischer Typ.
// Da der Typ-Parameter `T` generisch ist, kann es alles sein, einschließlich des konkreten Typs `A` oben definiert.
struct SingleGen<T>(T);
fn main() {
// `Single` ist konkret und nimmt explizit `A` an.
let _s = Single(A);
// Erstellen Sie eine Variable `_char` vom Typ `SingleGen<char>`
// und geben Sie ihr den Wert `SingleGen('a')`.
// Hier ist der Typ-Parameter von `SingleGen` explizit angegeben.
let _char: SingleGen<char> = SingleGen('a');
// `SingleGen` kann auch einen Typ-Parameter implizit angegeben haben:
let _t = SingleGen(A); // Verwendet `A` oben definiert.
let _i32 = SingleGen(6); // Verwendet `i32`.
let _char = SingleGen('a'); // Verwendet `char`.
}
Zusammenfassung
Herzlichen Glückwunsch! Sie haben das Generics-Lab abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.