Drop - Rust By Example
Description: Rust by Example (RBE) is a collection of runnable examples that illustrate various Rust concepts and standard libraries.

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Drop

The `Drop` trait only has one method: `drop`, which is called automatically when an object goes out of scope. The main use of the `Drop` trait is to free the resources that the implementor instance owns.

`Box`, `Vec`, `String`, `File`, and `Process` are some examples of types that implement the `Drop` trait to free resources. The `Drop` trait can also be manually implemented for any custom data type.

The following example adds a print to console to the `drop` function to announce when it is called.

    struct Droppable {
        name: &'static str,
    }

    // This trivial implementation of `drop` adds a print to console.
    impl Drop for Droppable {
        fn drop(&mut self) {
            println!("> Dropping {}", self.name);
        }
    }

    fn main() {
        let _a = Droppable { name: "a" };

        // block A
        {
            let _b = Droppable { name: "b" };

            // block B
            {
                let _c = Droppable { name: "c" };
                let _d = Droppable { name: "d" };

                println!("Exiting block B");
            }
            println!("Just exited block B");

            println!("Exiting block A");
        }
        println!("Just exited block A");

        // Variable can be manually dropped using the `drop` function
        drop(_a);
        // TODO ^ Try commenting this line

        println!("end of the main function");

        // `_a` *won't* be `drop`ed again here, because it already has been
        // (manually) `drop`ed
    }

For a more practical example, here’s how the `Drop` trait can be used to automatically clean up temporary files when they’re no longer needed:

    use std::fs::File;
    use std::path::PathBuf;

    struct TempFile {
        file: File,
        path: PathBuf,
    }

    impl TempFile {
        fn new(path: PathBuf) -> std::io::Result<Self> {
            // Note: File::create() will overwrite existing files
            let file = File::create(&path)?;

            Ok(Self { file, path })
        }
    }

    // When TempFile is dropped:
    // 1. First, our drop implementation will remove the file's name from the filesystem.
    // 2. Then, File's drop will close the file, removing its underlying content from the disk.
    impl Drop for TempFile {
        fn drop(&mut self) {
            if let Err(e) = std::fs::remove_file(&self.path) {
                eprintln!("Failed to remove temporary file: {}", e);
            }
            println!("> Dropped temporary file: {:?}", self.path);
            // File's drop is implicitly called here because it is a field of this struct.
        }
    }

    fn main() -> std::io::Result<()> {
        // Create a new scope to demonstrate drop behavior
        {
            let temp = TempFile::new("test.txt".into())?;
            println!("Temporary file created");
            // File will be automatically cleaned up when temp goes out of scope
        }
        println!("End of scope - file should be cleaned up");

        // We can also manually drop if needed
        let temp2 = TempFile::new("another_test.txt".into())?;
        drop(temp2); // Explicitly drop the file
        println!("Manually dropped file");

        Ok(())
    }