スコープガード
スコープガードは Drop トレイトを使って、スコープを抜けるときに、アンワインド中であっても自動的にクリーンアップコードを実行します。
// Copyright 2025 Google LLC // SPDX-License-Identifier: Apache-2.0 use scopeguard::{ScopeGuard, guard}; use std::fs::{self, File}; use std::io::Write; fn download_successful() -> bool { // [...] true } fn main() { let path = "download.tmp"; let mut file = File::create(path).expect("一時ファイルを作成できません"); // ファイル作成の直後にクリーンアップを設定する let cleanup = guard(path, |path| { println!("ダウンロードに失敗したため削除します: {:?}", path); let _ = fs::remove_file(path); }); writeln!(file, "partial data...").unwrap(); if download_successful() { // ダウンロードに成功したら、ファイルを残す let path = ScopeGuard::into_inner(cleanup); println!("ダウンロード '{path}' が完了しました!"); } // それ以外の場合は、ガードが実行されてファイルを削除する }
-
この例はダウンロードのワークフローをモデル化したものです。最初に一時ファイルを作成し、その後、ダウンロードが失敗した場合にそのファイルが削除されるようスコープガードを使います。
-
scopeguardクレートを使うと、カスタムのDrop実装を持つ独自の型を定義しなくても、単発のDropベースのクリーンアップを簡単に定義できます。 -
ガードはファイル作成の直後に作成されるため、
writeln!()が失敗してもファイルは確実にクリーンアップされます。この順序は正しさのために不可欠です。 -
guard()はScopeGuardインスタンスを作成します。これはユーザー定義の値(この場合はpath)と、後でその値を受け取るクリーンアップ用クロージャを受け取ります。 -
ガードのクロージャは、
ScopeGuard::into_innerで 無効化 されない限り、スコープ終了時に実行されます(値を取り出すことで、drop 時にガードが何もしなくなります)。成功パスではinto_innerを呼び出すため、ガードはファイルを削除しません。 -
スコープガードは Go の
defer機能に似ています。 -
このパターンは「失敗時のクリーンアップ」のシナリオに最適で、成功パスが明示的に選ばれない限り、デフォルトでクリーンアップを実行すべき場合に適しています。
-
このパターンは、リソースオブジェクトのクリーンアップ戦略を自分で制御できない場合にも有用です。この例では、
File::drop()はファイルを閉じますが、削除はしません。 -
scopeguardクレートは、Strategyトレイトを介したクリーンアップ戦略もサポートしています。ガードをアンワインド時のみ、または成功時のみに実行するよう選べるため、単に常に実行するだけではありません。