Rust in Depth

the Drop trait

When a value owns a resource — heap memory, an open file, a network connection, a held lock — something has to release it when you are done. In C you call free() or close() by hand and hope you never forget; forgetting leaks the resource, and freeing twice or freeing on every error path is its own source of bugs. Rust ties cleanup to ownership and scope: when an owning value goes out of scope, its cleanup runs automatically. The Drop trait is how you say WHAT that cleanup is for your own type — it is Rust's destructor.

You implement it by writing impl Drop for YourType { fn drop(&mut self) { /* release the resource */ } }. The method's body is your cleanup code, and you do not call it — the compiler inserts a call to it automatically at the exact point the value's scope ends, in reverse order of declaration (the last value created is dropped first). This is the same RAII idea as C++ destructors: acquiring the resource in a constructor-like step and releasing it in drop means the resource is tied to the value's lifetime, and the end of scope IS the release, so you cannot forget it and it happens on every exit path including early returns and panics. A File closes itself when it drops; a MutexGuard unlocks when it drops; a Box frees its heap allocation when it drops; an Rc decrements its count when it drops. You rarely write Drop yourself for plain data (the fields' own drops handle it recursively) — you write it when your type manages a resource the compiler does not already know how to release, such as a raw handle from an FFI call.

Why this matters: Drop plus ownership is what gives Rust deterministic, automatic resource management without a garbage collector — cleanup happens at a known point (scope's end), not whenever a collector decides to run. Several honest details matter. You cannot call drop(&mut self) yourself, and you cannot drop a value twice; to release something early you pass it to the std::mem::drop function (which just takes ownership and lets scope end immediately). Drop runs on a panic too (this 'unwinding' is how locks get released even when a thread is crashing), but a drop method that itself panics during an unwind aborts the program. And a Drop type is not Copy — moving it transfers the single cleanup responsibility, never duplicating it. Finally, Rust does not GUARANTEE drop runs: leaking a value on purpose (std::mem::forget, or a reference cycle of Rc) skips it, so Drop is for releasing resources reliably on the normal paths, not a hard safety guarantee that it can never be skipped.

struct Guard { name: String } impl Drop for Guard { fn drop(&mut self) { println!("releasing {}", self.name); } } fn main() { let _a = Guard { name: String::from("a") }; let _b = Guard { name: String::from("b") }; println!("working"); } // scope ends -> drop runs in REVERSE order: // prints: working / releasing b / releasing a

Drop runs automatically at scope's end, in reverse declaration order — cleanup tied to ownership, on every exit path including panics.

You cannot call .drop() yourself or drop a value twice; use std::mem::drop to release early. Rust does NOT guarantee drop runs — std::mem::forget or an Rc cycle skips it — so Drop reliably releases on normal paths but is not an unbreakable safety guarantee.

Also called
DropdestructorRAII in Rustcleanup code解構清理資源釋放