SyntaxStudy
Sign Up
Rust Scope, Drop, and the Drop Trait
Rust Beginner 1 min read

Scope, Drop, and the Drop Trait

In Rust, values are dropped — their memory is freed and cleanup code is run — at the end of the scope in which they were created. Scopes are delimited by curly braces, and the compiler inserts the equivalent of a destructor call at precisely the point where each variable goes out of scope. This determinism, sometimes called RAII (Resource Acquisition Is Initialization), ensures resources like file handles, network connections, and heap memory are always released promptly. You can implement the `Drop` trait to run custom cleanup code when a value is destroyed. The trait has a single method, `drop(&mut self)`, called automatically by the compiler. You cannot call `drop` directly on a value — instead, use `std::mem::drop(value)` to explicitly drop a value before its scope ends. This is useful for releasing a mutex lock early or closing a file before returning. The interaction between ownership and drop guarantees that every resource is cleaned up exactly once. Since there is only ever one owner, the owner's drop runs once, and no other path can drop the same resource. This eliminates double-free errors entirely at compile time, a class of vulnerability that affects C and C++ programs.
Example
struct Connection {
    name: String,
}

impl Connection {
    fn new(name: &str) -> Self {
        println!("[{name}] opened");
        Connection { name: name.to_string() }
    }
}

impl Drop for Connection {
    fn drop(&mut self) {
        println!("[{}] closed", self.name);
    }
}

fn main() {
    let _outer = Connection::new("outer");

    {
        let _inner = Connection::new("inner");
        println!("inside inner scope");
    } // _inner is dropped here → "[inner] closed"

    println!("after inner scope");

    let early = Connection::new("early");
    println!("about to drop 'early' explicitly");
    drop(early);   // std::mem::drop — drops before end of scope
    println!("'early' has been dropped");

    // _outer is dropped here at the end of main → "[outer] closed"
}

// Expected output:
// [outer] opened
// [inner] opened
// inside inner scope
// [inner] closed
// after inner scope
// [early] opened
// about to drop 'early' explicitly
// [early] closed
// 'early' has been dropped
// [outer] closed