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::dropfinishes.
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.