El Trait Drop
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 56 de 61.
Cuando un valor sale de alcance en Rust, se limpia automáticamente. Pero, ¿qué pasa si necesitas ejecutar código personalizado en ese momento, como registrar un log, liberar un recurso o enviar un mensaje final? El trait Drop te permite definir exactamente qué sucede cuando tu struct está a punto de ser destruido.
El trait Drop tiene un único método llamado drop que toma &mut self:
struct Connection {
id: u32,
}
impl Drop for Connection {
fn drop(&mut self) {
println!("Connection {} closed.", self.id);
}
}
Nunca llamas a drop directamente; Rust lo llama automáticamente cuando el valor sale de ámbito:
fn main() {
let conn = Connection { id: 42 };
println!("Using connection...");
} // "Connection 42 closed." se imprime aquí automáticamente
La salida sería:
Using connection...
Connection 42 closed.
Esta es la versión de Rust de un destructor. Se utiliza comúnmente para tareas de limpieza: cerrar descriptores de archivos, desconectarse de servidores o liberar recursos que Rust no puede gestionar automáticamente. El trait Drop garantiza que el código de limpieza se ejecute, incluso si el ámbito termina debido a un retorno anticipado.
Desafío
Fácil¡Vamos a construir un sistema de gestión de recursos que demuestre la limpieza automática! Crearás una estructura FileHandle que simula la apertura y el cierre de archivos; cuando el manejador salga del alcance, anunciará automáticamente que el archivo ha sido cerrado.
Organizarás tu código en dos archivos:
file_handle.rs: Define una estructuraFileHandlepública con un campofilenamepúblico (String). Implementa una función asociadanewque cree un FileHandle e imprima un mensaje cuando el archivo sea "abierto". Luego, implementa el traitDroppara que cuando el manejador sea liberado, imprima un mensaje de cierre.main.rs: Importa tu módulo file_handle y crea una función llamadaprocess_fileque reciba un nombre de archivo, cree un FileHandle dentro de un alcance local e imprima un mensaje de procesamiento mientras el archivo esté "abierto". La implementación de Drop se ejecutará automáticamente cuando termine el alcance. Llama a esta función con la entrada proporcionada.
Cuando se crea un FileHandle, debe imprimir:
Opening file: {filename}Mientras se procesa (dentro del alcance), imprime:
Processing {filename}...Cuando el FileHandle es liberado (termina el alcance), debe imprimir:
Closing file: {filename}Por ejemplo, con la entrada data.txt:
Opening file: data.txt
Processing data.txt...
Closing file: data.txtY con la entrada config.json:
Opening file: config.json
Processing config.json...
Closing file: config.jsonRecibirás una entrada: la cadena del nombre del archivo.
Hoja de referencia
El trait Drop te permite definir código de limpieza personalizado que se ejecuta automáticamente cuando un valor sale de su alcance.
El trait Drop tiene un único método llamado drop que toma &mut self:
struct Connection {
id: u32,
}
impl Drop for Connection {
fn drop(&mut self) {
println!("Connection {} closed.", self.id);
}
}
Nunca llamas a drop directamente; Rust lo llama automáticamente cuando el valor sale de su alcance:
fn main() {
let conn = Connection { id: 42 };
println!("Using connection...");
} // "Connection 42 closed." se imprime aquí automáticamente
El trait Drop se utiliza comúnmente para tareas de limpieza como cerrar descriptores de archivos, desconectarse de servidores o liberar recursos. Garantiza que tu código de limpieza se ejecute, incluso si el alcance termina debido a un retorno anticipado.
Pruébalo tú mismo
mod file_handle;
use file_handle::FileHandle;
// TODO: Implementar la función process_file
// Debería:
// 1. Crear un ámbito local (usando llaves {})
// 2. Dentro de ese ámbito, crear un FileHandle usando FileHandle::new()
// 3. Imprimir el mensaje de procesamiento: "Processing {filename}..."
// 4. Cuando el ámbito termine, Drop se llamará automáticamente
fn process_file(filename: &str) {
// TODO: Implementar esta función
}
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);
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Métodos y Comportamiento
Intro a Bloques de ImplementaciónEl Parámetro SelfMétodos MutablesFunciones AsociadasMúltiples Bloques de ImplementaciónEncadenamiento de MétodosResumen - Acciones de Rectángulo4Proyecto: Mascota virtual
Definir la mascotaAlimentar a la mascota7Traits estándar
El trait DebugEl trait DisplayClone y CopyTraits de igualdadResumen - Punto imprimible10Proyecto: Sistema de documentos
El Trait DrawComponente de texto2Encapsulamiento y módulos
Conceptos básicos de módulosLa palabra clave PublicCampos privadosGettersSettersRepaso - Casillero seguro5Genéricos
Estructuras genéricasMétodos genéricosMúltiples tipos genéricosFunciones genéricasResumen - Punto de coordenadas8Traits como límites
Sintaxis de límites de traitsLímites múltiplesLa cláusula whereRetornar tipos con traitsResumen: Impresora genérica11Patrones de diseño en Rust
Patrón NewtypeComposiciónEl Trait DropFrom e IntoResumen - Mock de Smart Pointer3Enums avanzados
Enums con datosMétodos en EnumsCoincidencia de variantes de datosEl Enum Option revisitadoResumen - Enum Shape6Definición de Traits
¿Qué es un Trait?Implementación de TraitsImplementaciones por defectoSobrescribir valores por defectoTraits con parámetrosResumen - Reproductor multimedia