Das Drop-Trait
Teil des Abschnitts Objektorientierte Programmierung der Rust-Journey von Coddy. Lektion 56 von 61.
Wenn ein Wert in Rust seinen Gültigkeitsbereich verlässt, wird er automatisch bereinigt. Aber was ist, wenn du in diesem Moment benutzerdefinierten Code ausführen musst, etwa zum Protokollieren, Freigeben einer Ressource oder Senden einer abschließenden Nachricht? Mit dem Trait Drop kannst du genau festlegen, was passiert, wenn dein Struct kurz davor ist, zerstört zu werden.
Das Merkmal Drop hat eine einzelne Methode namens drop, die &mut self übernimmt:
struct Connection {
id: u32,
}
impl Drop for Connection {
fn drop(&mut self) {
println!("Connection {} closed.", self.id);
}
}
Du rufst drop nie direkt auf: Rust ruft es automatisch auf, wenn der Wert den Gültigkeitsbereich verlässt:
fn main() {
let conn = Connection { id: 42 };
println!("Using connection...");
} // "Connection 42 closed." wird hier automatisch ausgegeben
Die Ausgabe wäre:
Using connection...
Connection 42 closed.
Dies ist Rusts Version eines Destruktors. Er wird häufig für Aufräumaufgaben verwendet: zum Schließen von Datei-Handles, zum Trennen von Serververbindungen oder zum Freigeben von Ressourcen, die Rust nicht automatisch verwalten kann. Das Drop-Trait garantiert, dass dein Aufräumcode ausgeführt wird, selbst wenn der Gültigkeitsbereich aufgrund einer vorzeitigen Rückgabe endet.
Aufgabe
EinfachErstellen wir ein Ressourcenverwaltungssystem, das die automatische Bereinigung demonstriert! Du erstellst eine FileHandle-Struktur, die das Öffnen und Schließen von Dateien simuliert. Wenn das Handle den Gültigkeitsbereich verlässt, gibt es automatisch bekannt, dass die Datei geschlossen wurde.
Du organisierst deinen Code auf zwei Dateien verteilt:
file_handle.rs: Definiere eine öffentlicheFileHandle-Struktur mit einem öffentlichenfilename-Feld (String). Implementiere eine zugehörigenew-Funktion, die ein FileHandle erstellt und eine Meldung ausgibt, wenn die Datei „geöffnet“ wird. Implementiere anschließend dasDrop-Trait, sodass beim Verwerfen des Handles eine Meldung zum Schließen ausgegeben wird.main.rs: Binde dein file_handle-Modul ein und erstelle eine Funktion namensprocess_file, die einen Dateinamen entgegennimmt, innerhalb eines lokalen Gültigkeitsbereichs ein FileHandle erstellt und eine Verarbeitungsmeldung ausgibt, während die Datei „geöffnet“ ist. Die Drop-Implementierung wird automatisch ausgeführt, wenn der Gültigkeitsbereich endet. Rufe diese Funktion mit der bereitgestellten Eingabe auf.
Wenn ein FileHandle erstellt wird, sollte Folgendes ausgegeben werden:
Opening file: {filename}Während der Verarbeitung (innerhalb des Gültigkeitsbereichs) soll Folgendes ausgegeben werden:
Processing {filename}...Wenn das FileHandle verworfen wird (der Gültigkeitsbereich endet), sollte Folgendes ausgegeben werden:
Closing file: {filename}Beispielsweise bei der Eingabe data.txt:
Opening file: data.txt
Processing data.txt...
Closing file: data.txtUnd bei der Eingabe config.json:
Opening file: config.json
Processing config.json...
Closing file: config.jsonDu erhältst eine Eingabe: die Dateinamen-Zeichenkette.
Probier es selbst
mod file_handle;
use file_handle::FileHandle;
// TODO: Implementiere die process_file-Funktion
// Sie sollte:
// 1. Einen lokalen Scope erstellen (mit geschweiften Klammern {})
// 2. Innerhalb dieses Scopes ein FileHandle mit FileHandle::new() erstellen
// 3. Die Verarbeitungsnachricht ausgeben: "Processing {filename}..."
// 4. Wenn der Scope endet, wird Drop automatisch aufgerufen
fn process_file(filename: &str) {
// TODO: Implementiere diese Funktion
}
fn main() {
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let filename = input.trim();
process_file(filename);
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Methoden und Verhalten
Einführung in ImplementierungsblöckeDer Self-ParameterVeränderliche MethodenAssoziierte FunktionenMehrere ImplementierungsblöckeMethod ChainingRückblick – Rechteck-Aktionen4Projekt: Virtuelles Haustier
Das Haustier definierenDas Haustier füttern7Standard-Traits
Das Debug-TraitDas Display-TraitClone und CopyGleichheits-TraitsZusammenfassung – Druckbarer Punkt10Projekt: Dokumentensystem
Das Draw-TraitText-Komponente2Kapselung und Module
Grundlagen der ModuleDas Public-SchlüsselwortPrivate FelderGetterSetterWiederholung – Sicherer Tresor5Generics
Generische StructsGenerische MethodenMehrere generische TypenGenerische FunktionenZusammenfassung - Koordinatenpunkt8Traits als Einschränkungen
Syntax für Trait BoundsMehrfache BoundsDie Where-KlauselTypen mit Traits zurückgebenRückblick – Generischer Drucker11Design Patterns in Rust
Newtype-PatternKompositionDas Drop-TraitFrom und IntoZusammenfassung – Smart Pointer Mock3Fortgeschrittene Enums
Enums mit DatenMethoden für EnumsMatching von DatenvariantenDas Option-Enum erneut betrachtetZusammenfassung – Shape-Enum6Definition von Traits
Was ist ein Trait?Traits implementierenStandardimplementierungenStandardimplementierungen überschreibenTraits mit ParameternZusammenfassung – Media PlayerÜbe selbstständig: Online-Rust-Compiler