Menu
Coddy logo textTech

Dynamischer Dispatch

Teil des Abschnitts Objektorientierte Programmierung der Rust-Journey von Coddy. Lektion 45 von 61.

Wenn du Generics mit Trait-Beschränkungen wie <T: Summary> verwendest, bestimmt Rust den genauen Typ zur Kompilierzeit. Dies wird als statischer Dispatch bezeichnet: Der Compiler generiert spezialisierten Code für jeden konkreten Typ, den du verwendest. Das ist schnell, aber es gibt eine Einschränkung: Eine Variable kann nur einen bestimmten Typ enthalten.

Was ist, wenn du eine einzelne Variable benötigst, die zur Laufzeit verschiedene Typen aufnehmen kann? Hier kommen Trait-Objekte ins Spiel. Mit Box<dyn Trait> kannst du jeden Typ speichern, der das Trait implementiert:

trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;

impl Speak for Dog {
    fn speak(&self) -> String { String::from("Woof!") }
}

impl Speak for Cat {
    fn speak(&self) -> String { String::from("Meow!") }
}

fn main() {
    let animal: Box<dyn Speak> = Box::new(Dog);
    println!("{}", animal.speak());  // "Woof!"
    
    let animal: Box<dyn Speak> = Box::new(Cat);
    println!("{}", animal.speak());  // "Meow!"
}

Das Schlüsselwort dyn kennzeichnet den dynamischen Dispatch: Rust ermittelt zur Laufzeit statt zur Kompilierungszeit, welche Methode aufgerufen werden soll. Box ist erforderlich, weil Trait-Objekte keine bekannte Größe haben; Box stellt einen Zeiger mit fester Größe bereit.

Stell es dir so vor: Generics sagen „Ich arbeite mit dem Typ T“, während Trait-Objekte sagen: „Ich arbeite mit allem, was dies tun kann.“ Der Kompromiss besteht in geringen Laufzeitkosten für die Flexibilität, verschiedene Typen über dieselbe Variable zu verarbeiten.

challenge icon

Aufgabe

Einfach

Lass uns ein Fahrzeugverleihsystem erstellen, das die Leistungsfähigkeit des dynamischen Dispatching demonstriert! Du wirst ein Trait erstellen, das definiert, was jedes mietbare Fahrzeug tun kann, und anschließend Box<dyn Trait> verwenden, um verschiedene Fahrzeugtypen in derselben Variable zu speichern.

Du wirst deinen Code auf zwei Dateien verteilen:

  • vehicle.rs: Definiere ein öffentliches Rentable-Trait mit einer rental_info-Methode, die &self entgegennimmt und einen String zurückgibt. Erstelle anschließend zwei öffentliche Strukturen:
    • Car: mit einem öffentlichen model-Feld (String). Die Methode rental_info soll Car: {model} zurückgeben.
    • Bike: mit einem öffentlichen brand-Feld (String). Die Methode rental_info soll Bike: {brand} zurückgeben.
  • main.rs: Binde dein Fahrzeugmodul ein und verwende die Eingaben, um dynamisches Dispatching zu demonstrieren. Erstelle eine Variable vom Typ Box<dyn Rentable>, die zunächst ein Car enthält, gib dessen Mietinformationen aus, weise derselben Variable anschließend ein Bike zu und gib dessen Mietinformationen erneut aus.

Das Faszinierende daran ist, dass eine einzelne Variable vom Typ Box<dyn Rentable> entweder ein Car oder ein Bike enthalten kann: Rust ermittelt zur Laufzeit, welche rental_info-Methode aufgerufen werden soll. Das ist dynamisches Dispatching in Aktion!

Deine Ausgabe sollte die Informationen beider Fahrzeuge anzeigen:

Car: {model}
Bike: {brand}

Zum Beispiel mit den Eingaben Tesla Model 3 und Trek:

Car: Tesla Model 3
Bike: Trek

Du erhältst zwei Eingaben: das Automodell und die Fahrradmarke.

Probier es selbst

mod vehicle;

use vehicle::{Rentable, Car, Bike};

fn main() {
    // Eingabe lesen
    let mut car_model = String::new();
    std::io::stdin().read_line(&mut car_model).expect("Failed to read line");
    let car_model = car_model.trim().to_string();
    
    let mut bike_brand = String::new();
    std::io::stdin().read_line(&mut bike_brand).expect("Failed to read line");
    let bike_brand = bike_brand.trim().to_string();
    
    // TODO: Erstelle eine Box<dyn Rentable>-Variable, die ein Car hält
    // Gib die Mietinformationen mit der rental_info()-Methode aus
    
    // TODO: Weise dieselbe Variable neu zu, sodass sie ein Bike hält
    // Gib die Mietinformationen erneut aus
    
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Rust-Compiler