← Back to Rust Course | Chapter 13: Smart Pointers & Unsafe | Lesson 5 of 7

The Drop Trait

Drop is a special goodbye method Rust calls automatically right before a value disappears for good.
Syntax
rust
impl Drop for Name {
    fn drop(&mut self) {
        // cleanup
    }
}

Implementing Drop

Implementing the Drop trait's drop method lets a type execute custom cleanup code automatically the moment its value's scope ends.

Example: Implementing Drop

markup
// Define a struct `Logger` to group related fields together
struct Logger {
    name: String,
}

// Implement the `Drop` trait for `Logger`
impl Drop for Logger {
    // Define the function `drop` taking `self`
    fn drop(&mut self) {
        // Print "Logger '{}' shutting down" to the console, substituting in `self.name` (with a trailing newline)
        println!("Logger '{}' shutting down", self.name);
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `_logger`, set to `Logger { name: String::from("main-logger") }`
    let _logger = Logger { name: String::from("main-logger") };
    // Print "Logger is active" to the console (with a trailing newline)
    println!("Logger is active");
}

Forcing an Early Drop

Since calling .drop() directly is disallowed by the compiler, std::mem::drop(value) is used to force a value to be cleaned up earlier than the end of its natural scope.

Example: Forcing an Early Drop

markup
// Define a struct `Resource` to group related fields together
struct Resource;

// Implement the `Drop` trait for `Resource`
impl Drop for Resource {
    // Define the function `drop` taking `self`
    fn drop(&mut self) {
        // Print "Resource cleaned up" to the console (with a trailing newline)
        println!("Resource cleaned up");
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `res`, set to `Resource`
    let res = Resource;
    // Print "About to drop early" to the console (with a trailing newline)
    println!("About to drop early");
    drop(res);
    // Print "Dropped; continuing" to the console (with a trailing newline)
    println!("Dropped; continuing");
}

Drop Order Matches Reverse Declaration

When several values with Drop implementations go out of scope together, they are cleaned up in the reverse order they were declared, similar to unwinding a stack.

Example: Drop Order Matches Reverse Declaration

markup
// Define a struct `Item` to group related fields together
struct Item(i32);

// Implement the `Drop` trait for `Item`
impl Drop for Item {
    // Define the function `drop` taking `self`
    fn drop(&mut self) {
        // Print "Dropping item {}" to the console, substituting in `self.0` (with a trailing newline)
        println!("Dropping item {}", self.0);
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `_a`, set to `Item(1)`
    let _a = Item(1);
    // Declare an immutable variable `_b`, set to `Item(2)`
    let _b = Item(2);
    // Declare an immutable variable `_c`, set to `Item(3)`
    let _c = Item(3);
    // Print "All items created" to the console (with a trailing newline)
    println!("All items created");
}

A Practical Use: Resource Cleanup

Drop is commonly used to guarantee cleanup logic, like closing a connection, always runs -- even if the function returns early -- since the value is dropped whenever its scope ends.

Example: A Practical Use: Resource Cleanup

markup
// Define a struct `Connection` to group related fields together
struct Connection {
    id: u32,
}

// Implement the `Drop` trait for `Connection`
impl Drop for Connection {
    // Define the function `drop` taking `self`
    fn drop(&mut self) {
        // Print "Closing connection #{}" to the console, substituting in `self.id` (with a trailing newline)
        println!("Closing connection #{}", self.id);
    }
}

// Define the function `use_connection` with no parameters
fn use_connection() {
    // Declare an immutable variable `_conn`, set to `Connection { id: 7 }`
    let _conn = Connection { id: 7 };
    // Print "Using connection #7" to the console (with a trailing newline)
    println!("Using connection #7");
}

// Entry point: execution of the program starts here
fn main() {
    use_connection();
    // Print "Connection was closed automatically" to the console (with a trailing newline)
    println!("Connection was closed automatically");
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Trying to call .drop() directly on a value -- Rust forbids this explicitly and provides std::mem::drop instead.
  2. Assuming Drop::drop runs immediately when a value is moved -- it only runs when the value's owner truly goes out of scope.
  3. Forgetting values are dropped in reverse declaration order within the same scope, which can matter for cleanup ordering.
Chapter Summary
  • Implementing Drop lets a type run custom cleanup logic automatically when its value goes out of scope.
  • You cannot call the drop method directly; use the free function std::mem::drop(value) to force an early drop.
  • Values are dropped in reverse order of their declaration within a scope.
  • Drop is commonly used for releasing resources like file handles, locks, or network connections.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.