Menu
Coddy logo textTech

Standardimplementierungen

Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 31 von 61.

Bisher war jede Trait-Methode, die wir definiert haben, nur eine Signatur – eine Anforderung ohne Rumpf. Aber was ist, wenn die meisten Typen, die einen Trait implementieren, dieselbe Logik verwenden würden? Rust ermöglicht es dir, eine Standardimplementierung direkt in der Trait-Definition bereitzustellen.

Anstatt die Methodensignatur mit einem Semikolon zu beenden, fügen Sie einen Rumpf hinzu:

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

Jetzt erhält jeder Typ, der Greet implementiert, automatisch diese Methode – ohne dass Code im impl-Block geschrieben werden muss:

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // Hallo!

Das leere impl Greet for Guest {} ist gültig, da der Trait bereits das Verhalten bereitstellt. Die Struct entscheidet sich einfach für den Trait und erhält die Standardmethode kostenlos.

Dieses Muster ist nützlich, wenn Sie gemeinsames Verhalten definieren möchten, das in den meisten Fällen funktioniert. Typen, die etwas anderes benötigen, können den Standard überschreiben (was Sie als Nächstes lernen werden), während Typen, die mit dem Standardverhalten zufrieden sind, sich nicht wiederholen müssen.

challenge icon

Aufgabe

Einfach

Lassen Sie uns die Stärke von Standardimplementierungen erkunden, indem wir ein Benachrichtigungssystem bauen! Sie werden ein Trait erstellen, das standardmäßiges Verhalten direkt mitliefert, sodass Typen dieses nutzen können, ohne repetitiven Code schreiben zu müssen.

Sie werden Ihren Code über drei Dateien organisieren:

  • notifiable.rs: Definieren Sie ein öffentliches Notifiable-Trait mit einer notify(&self) -> String-Methode, die eine Standardimplementierung besitzt. Der Standardwert sollte "You have a new notification!" zurückgeben. Jeder Typ, der dieses Trait implementiert, erhält automatisch dieses Verhalten, ohne etwas in seinen impl-Block schreiben zu müssen.
  • alerts.rs: Erstellen Sie zwei einfache öffentliche Unit-Structs, die Ihr Trait implementieren:
    • EmailAlert — implementiert Notifiable mit einem leeren impl-Block (verwendet den Standard)
    • SystemAlert — implementiert ebenfalls Notifiable mit einem leeren impl-Block (verwendet den Standard)
    Beide Structs erhalten automatisch die Standard-Benachrichtigungsmeldung, ohne dass Sie Methodenrümpfe schreiben müssen!
  • main.rs: Führen Sie Ihre Module zusammen und demonstrieren Sie, wie beide Alert-Typen dasselbe Standardverhalten teilen. Erstellen Sie Instanzen beider Structs und rufen Sie deren notify-Methoden auf.

Erstellen Sie in Ihrer Hauptdatei ein EmailAlert und ein SystemAlert und geben Sie deren Benachrichtigungen in separaten Zeilen aus.

Ihre Ausgabe sollte wie folgt aussehen:

You have a new notification!
You have a new notification!

Beachten Sie, dass beide Typen die identische Ausgabe erzeugen – das ist das Schöne an Standardimplementierungen! Keine der Structs musste Code für die notify-Methode schreiben, und dennoch verfügen beide über ein voll funktionsfähiges Benachrichtigungsverhalten. In der nächsten Lektion lernen Sie, wie Sie diese Standards überschreiben können, wenn ein Typ ein benutzerdefiniertes Verhalten benötigt.

Spickzettel

Trait-Methoden können Standardimplementierungen haben, indem ein Methodenkörper anstelle von nur einer Signatur bereitgestellt wird:

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

Typen, die das Trait implementieren, erhalten automatisch das Standardverhalten, ohne dass Code geschrieben werden muss:

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // Hello there!

Ein leerer impl-Block ist gültig, wenn das Trait Standardimplementierungen bereitstellt. Dies ermöglicht es Typen, sich für gemeinsames Verhalten zu entscheiden, ohne Wiederholungen zu erzeugen.

Probier es selbst

mod notifiable;
mod alerts;

use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};

fn main() {
    // TODO: Erstelle eine Instanz von EmailAlert
    
    // TODO: Erstelle eine Instanz von SystemAlert
    
    // TODO: Gib die Benachrichtigung von EmailAlert aus
    
    // TODO: Gib die Benachrichtigung von SystemAlert 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 Object Oriented Programming