言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Rust辞典

  1. トップページ
  2. Rust辞典
  3. Drop トレイト / スコープと解放

Drop トレイト / スコープと解放

対応: Rust 1.0(2015)

DropトレイトはRustのRAII(Resource Acquisition Is Initialization)パターンを実現する仕組みで、値がスコープを抜けるときに自動的にクリーンアップ処理を実行します。

構文

// Dropトレイトの実装
impl Drop for 型名 {
    fn drop(&mut self) {
        // スコープを抜けるときに自動呼び出されます
    }
}

// 早期解放(std::mem::drop関数を使います)
drop(変数);

概要一覧

項目概要
Drop::drop()値がスコープを抜けるときに自動的に呼ばれるメソッドです。直接呼び出すことはできません。
drop()関数標準ライブラリのdrop()関数で所有権を受け取り、即座にスコープを終了させます。
解放順序ローカル変数は宣言の逆順(後に宣言したものが先)に解放されます。ただし構造体フィールドは宣言順(先に宣言したものが先)に解放されます。
RAIIパターンRAII(Resource Acquisition Is Initialization)とは、リソースの確保と解放を変数のライフサイクルに紐づけるパターンです。ファイルハンドル・ロック・ネットワーク接続などのリソース管理に活用されます。

サンプルコード

drop_scope.rs
struct Resource {
    name: String,
}

impl Drop for Resource {
    fn drop(&mut self) {
        println!("{}を解放しました", self.name);
    }
}

fn main() {
    let r1 = Resource { name: String::from("リソース1") };
    {
        let r2 = Resource { name: String::from("リソース2") };
        let r3 = Resource { name: String::from("リソース3") };
        println!("内側のスコープです");
    } // r3, r2の順で解放されます(宣言の逆順)

    println!("外側のスコープに戻りました");

    let r4 = Resource { name: String::from("リソース4") };
    drop(r4); // 早期解放します
    println!("r4は解放済みです");
} // r1が解放されます
rustc drop_scope.rs
./drop_scope
内側のスコープです
リソース3を解放しました
リソース2を解放しました
外側のスコープに戻りました
リソース4を解放しました
r4は解放済みです
リソース1を解放しました
drop_scope2.rs
use std::fs::File;
use std::io::Write;

struct ManagedFile {
    name: String,
    file: File,
}

impl ManagedFile {
    fn new(name: &str) -> Self {
        let file = File::create(name).expect("ファイル作成に失敗しました");
        println!("ファイルを開きました: {}", name);
        ManagedFile {
            name: name.to_string(),
            file,
        }
    }

    fn write(&mut self, data: &str) {
        self.file.write_all(data.as_bytes()).expect("書き込みに失敗しました");
    }
}

impl Drop for ManagedFile {
    fn drop(&mut self) {
        // スコープを抜けると自動的にファイルが閉じられます
        println!("ファイルを閉じました: {}", self.name);
    }
}

fn main() {
    {
        let mut mf = ManagedFile::new("output.txt");
        mf.write("Kogami Shinya\n");
        mf.write("Tsunemori Akane\n");
        println!("データを書き込みました");
    } // ここでDropが呼ばれてファイルが自動クローズされます

    println!("スコープを抜けました");
    std::fs::remove_file("output.txt").ok(); // 後始末
}
rustc drop_scope2.rs
./drop_scope2
ファイルを開きました: output.txt
データを書き込みました
ファイルを閉じました: output.txt
スコープを抜けました
drop_scope3.rs
struct Layer {
    label: String,
}

impl Drop for Layer {
    fn drop(&mut self) {
        println!("drop: {}", self.label);
    }
}

struct Stack {
    bottom: Layer, // 先に宣言
    top: Layer,    // 後に宣言
}

impl Drop for Stack {
    fn drop(&mut self) {
        println!("Stack 全体を解放します");
        // フィールドの解放はこのdropの後、宣言順(bottom→top)で行われます
    }
}

fn main() {
    let _s = Stack {
        bottom: Layer { label: String::from("bottom") },
        top:    Layer { label: String::from("top") },
    };
    println!("スタックを作成しました");
} // Stack::drop → bottom → top の順で解放されます
rustc drop_scope3.rs
./drop_scope3
スタックを作成しました
Stack 全体を解放します
drop: bottom
drop: top

概要

Dropトレイトはメモリだけでなく、ファイルのクローズ・Mutexのロック解除・ネットワーク接続の切断など、あらゆるリソース管理に使用できます。Rustの標準ライブラリの多くの型(File・MutexGuard など)がDropを実装しています。

Drop::drop()メソッドを直接呼び出すことはできません。早期解放が必要な場合は必ず標準ライブラリの『drop()』関数を使用してください。

CopyトレイトとDropトレイトは同一の型に共存できません。Copyを実装したい場合はClone / Copyトレイトを参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。