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トレイトを参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。