Охранники области видимости
Охранник области видимости использует трейт 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("cannot create temporary file");
// Настраиваем очистку сразу после создания файла
let cleanup = guard(path, |path| {
println!("download failed, deleting: {:?}", path);
let _ = fs::remove_file(path);
});
writeln!(file, "partial data...").unwrap();
if download_successful() {
// Загрузка успешна, сохраняем файл
let path = ScopeGuard::into_inner(cleanup);
println!("Download '{path}' complete!");
}
// Иначе охранник срабатывает и удаляет файл
}
-
Этот пример моделирует процесс загрузки. Сначала мы создаём временный файл, затем используем охранник области видимости, чтобы гарантировать удаление файла, если загрузка не удалась.
-
Крейт
scopeguardпозволяет удобно определить одноразовую очистку на основеDrop, не определяя собственный тип с собственной реализациейDrop. -
Охранник создаётся сразу после создания файла, поэтому даже если
writeln!()завершится с ошибкой, файл всё равно будет очищен. Такой порядок необходим для корректности. -
guard()создаёт экземплярScopeGuard. Он принимает значение, определённое пользователем (в данном случаеpath), и замыкание очистки, которое позже получит это значение. -
Замыкание охранника выполняется при выходе из области видимости, если только оно не обезврежено через
ScopeGuard::into_inner(извлечение значения, чтобы охранник ничего не делал при освобождении). На пути успеха мы вызываемinto_inner, поэтому охранник не удалит файл. -
Охранник области видимости похож на функцию
deferв Go. -
Этот паттерн идеален для сценариев «очистка при неудаче», где очистка должна выполняться по умолчанию, если только не выбран путь успеха явно.
-
Этот паттерн также полезен, когда вы не контролируете стратегию очистки объекта ресурса. В этом примере
File::drop()закрывает файл, но не удаляет его. -
Крейт
scopeguardтакже поддерживает стратегии очистки через трейтStrategy. Можно выбрать, запускать ли охранник только при раскручивании или только при успехе, а не всегда.