Drop トレイト

Drop を実装する値は、スコープを抜けるときに実行するコードを指定できます:

// 著作権 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

struct Droppable {
    name: &'static str,
}

impl Drop for Droppable {
    fn drop(&mut self) {
        println!("Dropping {}", self.name);
    }
}

fn main() {
    let a = Droppable { name: "a" };
    {
        let b = Droppable { name: "b" };
        {
            let c = Droppable { name: "c" };
            let d = Droppable { name: "d" };
            println!("Exiting innermost block");
        }
        println!("Exiting next block");
    }
    drop(a);
    println!("Exiting main");
}
  • std::mem::dropstd::ops::Drop::drop と同じではないことに注意してください。
  • 値はスコープを抜けると自動的にドロップされます。
  • 値がドロップされるとき、その値が std::ops::Drop を実装していれば、その Drop::drop 実装が呼び出されます。
  • その後、そのすべてのフィールドも、それ自体が Drop を実装しているかどうかに かかわらずドロップされます。
  • std::mem::drop は、任意の値を受け取るだけの空の関数です。重要なのは、その値の 所有権を取得することです。そのため、そのスコープの終わりで値がドロップされます。 これにより、本来ならスコープを抜けるまで残る値を、より早い段階で明示的に ドロップするための便利な方法になります。
    • これは、drop 時に何らかの処理を行うオブジェクト、たとえばロックの解放や ファイルを閉じることなどに役立ちます。

議論のポイント:

  • なぜ Drop::dropself を受け取らないのでしょうか?
    • 簡単に言うと、もしそうだとすると、ブロックの終わりで std::mem::drop が 呼び出され、その結果 Drop::drop がもう一度呼び出されて、 スタックオーバーフローになります!
  • drop(a)a.drop() に置き換えてみてください。