ドロップ
Drop
トレイトにはメソッドが一つだけしかありません。drop
です。これは、オブジェクトがスコープから抜けた時に自動で呼ばれます。Drop
トレイトの主な使用目的は、インスタンスが所有する資源を開放することです。
Drop
トレイトを実装している型の例としてはBox
、Vec
、String
、File
、Process
等があげられます。Drop
トレイトは任意の型に対して手動で実装することができます。
以下の例ではdrop
メソッドにコンソールへの出力を追加することで、drop
が呼ばれたタイミングが分かるようにしています。
struct Droppable { name: &'static str, } // このちょっとした実装で、`drop`にコンソール出力機能がつきます。 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"); // `drop`関数を用いて変数を手動で開放することもできます。 drop(_a); // TODO ^ この行をコメントアウトしてみましょう。 println!("end of the main function"); // `_a`はここで`drop`されることは *ありません* 。なぜならば、上ですでに // (手動で)`drop`されているためです。 }
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, the File will be automatically closed (Drop for File) // 2. Then our drop implementation will remove the file impl Drop for TempFile { fn drop(&mut self) { // Note: File is already closed at this point if let Err(e) = std::fs::remove_file(&self.path) { eprintln!("Failed to remove temporary file: {}", e); } println!("> Dropped temporary file: {:?}", self.path); } } 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(()) }