Il trait Drop
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 56 di 61.
Quando un valore esce dal suo ambito in Rust, viene ripulito automaticamente. Ma cosa succede se devi eseguire del codice personalizzato in quel momento, come registrare un log, rilasciare una risorsa o inviare un messaggio finale? Il trait Drop ti permette di definire esattamente cosa succede quando la tua struct sta per essere distrutta.
Il trait Drop ha un unico metodo chiamato drop che accetta &mut self:
struct Connection {
id: u32,
}
impl Drop for Connection {
fn drop(&mut self) {
println!("Connection {} closed.", self.id);
}
}
Non chiami mai drop direttamente: Rust lo chiama automaticamente quando il valore esce dal suo ambito:
fn main() {
let conn = Connection { id: 42 };
println!("Using connection...");
} // "Connection 42 closed." prints here automatically
L'output sarebbe:
Using connection...
Connection 42 closed.
Questa è la versione di Rust di un distruttore. Viene comunemente usata per le operazioni di pulizia: chiudere i gestori di file, disconnettersi dai server o liberare risorse che Rust non può gestire automaticamente. Il trait Drop garantisce che il codice di pulizia venga eseguito, anche se l'ambito termina a causa di un return anticipato.
Sfida
FacileCostruiamo un sistema di gestione delle risorse che dimostri la pulizia automatica! Creerai una struct FileHandle che simula l'apertura e la chiusura dei file; quando l'handle esce dallo scope, annuncerà automaticamente che il file è stato chiuso.
Organizzerai il codice in due file:
file_handle.rs: Definisci una struct pubblicaFileHandlecon un campo pubblicofilename(String). Implementa una funzione associatanewche crea un FileHandle e stampa un messaggio quando il file viene "aperto". Poi implementa il traitDropin modo che, quando l'handle viene eliminato, stampi un messaggio di chiusura.main.rs: Includi il tuo modulo file_handle e crea una funzione chiamataprocess_fileche accetta un filename, crea un FileHandle all'interno di uno scope locale e stampa un messaggio di elaborazione mentre il file è "aperto". L'implementazione di Drop verrà eseguita automaticamente quando termina lo scope. Chiama questa funzione con l'input fornito.
Quando viene creato un FileHandle, dovrebbe stampare:
Opening file: {filename}Durante l'elaborazione (all'interno dello scope), stampa:
Processing {filename}...Quando il FileHandle viene eliminato (al termine dello scope), dovrebbe stampare:
Closing file: {filename}Per esempio, con l'input data.txt:
Opening file: data.txt
Processing data.txt...
Closing file: data.txtE con l'input config.json:
Opening file: config.json
Processing config.json...
Closing file: config.jsonRiceverai un input: la stringa del filename.
Provalo tu
mod file_handle;
use file_handle::FileHandle;
// TODO: Implementa la funzione process_file
// Deve:
// 1. Creare uno scope locale (usando le parentesi graffe {})
// 2. All'interno dello scope, creare un FileHandle usando FileHandle::new()
// 3. Stampare il messaggio di elaborazione: "Processing {filename}..."
// 4. Alla fine dello scope, Drop verrà chiamato automaticamente
fn process_file(filename: &str) {
// TODO: Implementa questa funzione
}
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);
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Metodi e comportamento
Introduzione ai blocchi implIl parametro selfMetodi mutabiliFunzioni associateBlocchi impl multipliConcatenamento di metodiRiepilogo - Azioni sul rettangolo4Progetto: animale domestico virtuale
Definire l'animaleNutrire l'animale7Trait standard
Il trait DebugIl trait DisplayClone e CopyTrait di uguaglianzaRiepilogo - Punto stampabile10Progetto: sistema di documenti
Il trait DrawComponente di testo2Incapsulamento e moduli
Nozioni di base sui moduliLa parola chiave publicCampi privatiGetterSetterRiepilogo - Armadietto sicuro5Generics
Struct genericheMetodi genericiPiù tipi genericiFunzioni genericheRipasso - Punto di coordinate8I Trait come vincoli
Sintassi dei vincoli sui traitVincoli multipliLa clausola whereRestituire tipi con i traitRiepilogo - Stampante generica11Modelli di progettazione in Rust
Pattern NewtypeComposizioneIl trait DropFrom e IntoRipasso - Mock con smart pointer3Enumerazioni avanzate
Enumerazioni con datiMetodi sulle enumerazioniCorrispondenza delle varianti con datiL'enumerazione Option ripresaRiepilogo - enumerazione Shape6Definizione dei trait
Che cos’è un trait?Implementare i traitImplementazioni predefiniteSovrascrivere le implementazioni predefiniteTrait con parametriRiepilogo - Lettore multimedialeEsercitati da solo: Compilatore Rust online