RAII

Las variables en Rust hacen más que solo almacenar datos en la pila: también poseen recursos, por ejemplo Box<T> posee memoria en la pila. Rust aplica RAII(Adquisición de recursos es inicialización), por lo que siempre que un objeto sale del ámbito, se llama a su destructor y se liberan sus recursos propios.

Este comportamiento protege contra errores de pérdida de recursos, por lo que nunca más tendrás que liberar memoria manualmente o preocuparte por las fugas de memoria. Aquí hay una muestra rápida:

// raii.rs
fn crea_box() {
    // Asigna un número entero en el montículo
    let _box1 = Box::new(3i32);

    // `_box1` se destruye aquí y la memoria se libera
}

fn main() {
    // Asignar un número entero en el montículo
    let _box2 = Box::new(5i32);

    // Un ámbito anidado:
    {
        // Asigna un número entero en el montículo
        let _box3 = Box::new(4i32);

        // `_box3` se destruye aquí y la memoria se libera
    }

    // Creando muchas cajas solo por diversión
    // ¡No es necesario liberar memoria manualmente!
    for _ in 0u32..1_000 {
        crea_box();
    }

    // `_box2` se destruye aquí y la memoria se libera
}

Por supuesto, podemos verificar los errores de memoria usando valgrind:

$ rustc raii.rs && valgrind ./raii
==26873== Memcheck, a memory error detector
==26873== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26873== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==26873== Command: ./raii
==26873==
==26873==
==26873== HEAP SUMMARY:
==26873==     in use at exit: 0 bytes in 0 blocks
==26873==   total heap usage: 1,013 allocs, 1,013 frees, 8,696 bytes allocated
==26873==
==26873== All heap blocks were freed -- no leaks are possible
==26873==
==26873== For counts of detected and suppressed errors, rerun with: -v
==26873== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

¡No hay fugas aquí!

Destructor

La noción de destructor en Rust se proporciona a través del rasgo Drop. Se llama al destructor cuando el recurso queda fuera de alcance. No es necesario implementar este rasgo para todos los tipos, solo impleméntalo para tu tipo si necesitas tu propia lógica de destructor.

Ejecuta el siguiente ejemplo para ver cómo funciona el rasgo Drop. Cuando la variable en la función main se sale ámbito, se invoca el destructor personalizado.

struct ParaDrop;

impl Drop for ParaDrop {
    fn drop(&mut self) {
        println!("ParaDrop está siendo destruido");
    }
}

fn main() {
    let x = ParaDrop;
    println!("¡Creé un ParaDrop!");
}

Ve también

Box