Essential Standard Traits

Drop

The Drop trait in std::ops defines a destructor (drop(&mut self)) that the compiler runs automatically whenever a value goes out of scope, releasing owned resources such as heap memory, file handles, network sockets, or locks.

Trait Definition

pub trait Drop {
    fn drop(&mut self);
}

This automatic deterministic cleanup is known as RAII (Resource Acquisition Is Initialisation). You never need to write impl Drop merely to free fields that are themselves String or Vec<T>—the compiler automatically drops every field of a struct or enum after running the type's own Drop::drop body.

Deterministic Drop Order

  • Local variables in a block are dropped in reverse declaration order (last in, first out).
  • Struct fields are dropped in declaration order (top to bottom) after the struct's Drop::drop finishes.
struct Guard(&'static str);

impl Drop for Guard {
    fn drop(&mut self) {
        println!("Dropping {}", self.0);
    }
}

fn main() {
    let _first = Guard("first");
    {
        let _inner = Guard("inner");
        println!("Inside inner block");
    }
    let _second = Guard("second");
    println!("End of main");
}
Inside inner block
Dropping inner
End of main
Dropping second
Dropping first

Explicit Early Cleanup with std::mem::drop

Calling value.drop() directly is forbidden by the compiler (E0040) because the compiler would still invoke Drop::drop a second time at the end of the scope, causing a double free:

// ❌ does not compile
struct Connection;

impl Drop for Connection {
    fn drop(&mut self) {}
}

fn main() {
    let mut conn = Connection;
    conn.drop();
}
error[E0040]: explicit use of destructor method
  --> src/main.rs:10:10
   |
10 |     conn.drop();
   |          ^^^^ explicit destructor calls not allowed
   |
help: consider using `drop` function
   |
10 |     drop(conn);
   |     +++++    ~

To release a value before the end of its lexical scope, pass it by value to the prelude function drop(value) (std::mem::drop), which is defined as:

pub fn drop<T>(_x: T) {}

Moving value into drop(value) transfers ownership into _x, which immediately goes out of scope at the end of drop and runs the destructor once.