Le trait Drop
Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 56 sur 61.
Lorsqu'une valeur sort de la portée en Rust, elle est automatiquement nettoyée. Mais que se passe-t-il si vous devez exécuter du code personnalisé à ce moment-là — comme la journalisation, la libération d'une ressource ou l'envoi d'un message final ? Le trait Drop vous permet de définir exactement ce qui se passe lorsque votre structure est sur le point d'être détruite.
Le trait Drop possède une seule méthode appelée drop qui prend &mut self :
struct Connection {
id: u32,
}
impl Drop for Connection {
fn drop(&mut self) {
println!("Connection {} closed.", self.id);
}
}
Vous n'appelez jamais drop directement — Rust l'appelle automatiquement lorsque la valeur sort de la portée :
fn main() {
let conn = Connection { id: 42 };
println!("Using connection...");
} // "Connection 42 closed." s'affiche ici automatiquement
Le résultat serait :
Using connection...
Connection 42 closed.
C'est la version Rust d'un destructeur. Il est couramment utilisé pour les tâches de nettoyage : fermeture de descripteurs de fichiers, déconnexion de serveurs ou libération de ressources que Rust ne peut pas gérer automatiquement. Le trait Drop garantit que votre code de nettoyage s'exécute, même si la portée se termine en raison d'un retour anticipé.
Défi
FacileConstruisons un système de gestion de ressources qui démontre le nettoyage automatique ! Vous allez créer une structure FileHandle qui simule l'ouverture et la fermeture de fichiers—lorsque le handle sort de la portée (scope), il annoncera automatiquement que le fichier a été fermé.
Vous organiserez votre code sur deux fichiers :
file_handle.rs: Définissez une structure publiqueFileHandleavec un champ publicfilename(String). Implémentez une fonction associéenewqui crée un FileHandle et affiche un message lorsque le fichier est "ouvert". Ensuite, implémentez le traitDropde sorte que lorsque le handle est supprimé, il affiche un message de fermeture.main.rs: Importez votre module file_handle et créez une fonction appeléeprocess_filequi prend un nom de fichier, crée un FileHandle à l'intérieur d'une portée locale, et affiche un message de traitement pendant que le fichier est "ouvert". L'implémentation de Drop s'exécutera automatiquement à la fin de la portée. Appelez cette fonction avec l'entrée fournie.
Lorsqu'un FileHandle est créé, il doit afficher :
Opening file: {filename}Pendant le traitement (à l'intérieur de la portée), affichez :
Processing {filename}...Lorsque le FileHandle est supprimé (fin de la portée), il doit afficher :
Closing file: {filename}Par exemple, avec l'entrée data.txt :
Opening file: data.txt
Processing data.txt...
Closing file: data.txtEt avec l'entrée config.json :
Opening file: config.json
Processing config.json...
Closing file: config.jsonVous recevrez une entrée : la chaîne de caractères du nom de fichier.
Aide-mémoire
Le trait Drop vous permet de définir du code de nettoyage personnalisé qui s'exécute automatiquement lorsqu'une valeur sort de la portée.
Le trait Drop possède une seule méthode appelée drop qui prend &mut self :
struct Connection {
id: u32,
}
impl Drop for Connection {
fn drop(&mut self) {
println!("Connection {} closed.", self.id);
}
}
Vous n'appelez jamais drop directement — Rust l'appelle automatiquement lorsque la valeur sort de la portée :
fn main() {
let conn = Connection { id: 42 };
println!("Using connection...");
} // "Connection 42 closed." s'affiche ici automatiquement
Le trait Drop est couramment utilisé pour des tâches de nettoyage comme la fermeture de descripteurs de fichiers, la déconnexion de serveurs ou la libération de ressources. Il garantit que votre code de nettoyage s'exécute, même si la portée se termine par un retour anticipé.
Essayez vous-même
mod file_handle;
use file_handle::FileHandle;
// TODO: Implémenter la fonction process_file
// Elle devrait :
// 1. Créer une portée locale (en utilisant des accolades {})
// 2. À l'intérieur de cette portée, créer un FileHandle en utilisant FileHandle::new()
// 3. Afficher le message de traitement : "Processing {filename}..."
// 4. Quand la portée se termine, Drop sera automatiquement appelé
fn process_file(filename: &str) {
// TODO: Implémenter cette fonction
}
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);
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Object Oriented Programming
1Méthodes et comportement
Introduction aux blocs d'implémentationLe paramètre SelfMéthodes mutablesFonctions associéesBlocs d'implémentation multiplesChaînage de méthodesRécapitulatif - Actions sur le rectangle4Projet : Animal virtuel
Définir l'animalNourrir l'animal7Traits standards
Le trait DebugLe trait DisplayClone et CopyLes traits d'égalitéRécapitulatif - Point affichable10Projet : Système de documents
Le trait DrawComposant texte2Encapsulation et modules
Bases des modulesLe mot-clé publicChamps privésGettersSettersRécapitulatif - Casier sécurisé5Généricité
Structures génériquesMéthodes génériquesPlusieurs types génériquesFonctions génériquesRécapitulatif - Point de coordonnées8Les Traits comme contraintes
Syntaxe des contraintes de traitContraintes multiplesLa clause whereRetourner des types avec des traitsRécapitulatif - Afficheur générique11Design Patterns en Rust
Le pattern NewtypeCompositionLe trait DropFrom et IntoRécapitulatif - Mock de Smart Pointer3Enums avancées
Enums avec donnéesMéthodes sur les EnumsMatching des variantes de donnéesL'Enum Option revisitéeRécapitulatif - Enum Shape6Définition des Traits
Qu'est-ce qu'un Trait ?Implémenter des TraitsImplémentations par défautRedéfinir les comportements par défautTraits avec paramètresRécapitulatif - Lecteur multimédia