Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Охранники области видимости

Охранник области видимости использует трейт 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. Можно выбрать, запускать ли охранник только при раскручивании или только при успехе, а не всегда.