Il trait Drop consente di definire una logica di pulizia personalizzata per una risorsa quando esce dal proprio ambito. Viene solitamente utilizzato per liberare risorse come file, risorse di rete, esterne e non sicure. Drop viene chiamato automaticamente dal compilatore.
Esempio:
struct FileWrapper { fd: i32, } impl Drop per FileWrapper { fn drop(&mut self) { println!("Chiusura fd: {}", self.fd); unsafe { libc::close(self.fd); } } } fn main() { let file = FileWrapper { fd: 42 }; } // drop viene chiamato automaticamente
Caratteristiche:
file.drop(), ma si può chiamare tramite std::mem::drop(file).panic!) all'interno di drop — questo porterà a "double panic" e chiusura forzata del processo.Domanda: Cosa succede se durante il drop() di una struttura si tenta di trasferire la proprietà di una risorsa in un'altra parte del programma — ad esempio, restituirla da drop?
Risposta: Non è possibile "salvare" o trasferire il valore di un campo della struttura durante drop a qualcun altro, se non al drop stesso; tentare di restituire o trasferire un valore porterà a un errore di compilazione o a violazioni della sicurezza della memoria (se si utilizza unsafe). Esempio di errore:
impl Drop per MyStruct { fn drop(&mut self) -> T { // Errore: Drop::drop non può restituire un valore! ... } }
Storia
Nel processore di file hanno dimenticato di implementare Drop per la struttura che avvolge direttamente un descrittore di file grezzo. Dopo centinaia di operazioni si verificava "superato il limite dei descrittori di file" — le risorse non venivano liberate.
Storia
Nella libreria di rete hanno implementato Drop per l'avvolgimento sopra una connessione TCP, ma durante drop si verificava un panico a causa dell'errore nella chiusura del socket. Questo portava alla chiusura forzata del thread in caso di double-panic (l'unico modo — evitare il panico in Drop!).
Storia
Nel sistema dei plugin hanno cercato di implementare la pulizia tramite Drop, creando nuove risorse durante drop (ad esempio, il logging su file). Questo ha portato a "già preso in prestito: BorrowMutError" a causa della chiamata ricorsiva di drop per strutture correlate e perdite di risorse.