Структура программы

Defer и ресурсы

Выбор между defer и формой using для File, порядок очистки и граница ошибки выполнения.

Эта страница описывает Топаз v5.17. Прежде чем считать её актуальной, сверьте поле version в /version.json со значением 5.17.

Используйте defer, когда перед выходом из лексической области нужно обязательно выполнить очистку. Если область владеет ровно одним File, более узкая инструкция using объединяет получение ресурса, дочернюю область и неявное закрытие.

Проверяем порядок очистки

Рядом с программой создайте текстовый файл defer-resources.txt с точным содержимым:

ready

Сохраните следующий код как defer-resources.tpz:

TOPAZ
function проверитьЗаметку(путь: string) -> Result<(), string> {
    using файл = open(путь)? {
        defer { print("body cleanup") }
        let заметка = файл.read()?
        print("note scalars: {заметка.scalars().length}")
    }

    print("resource scope closed")
    Ok(())
}

match проверитьЗаметку("defer-resources.txt") {
    case Ok(_) => print("done")
    case Err(сообщение) => print("error: {сообщение}")
}

Проверьте и запустите файл:

BASH
topaz check defer-resources.tpz
topaz run defer-resources.tpz

Строки появляются в следующем порядке:

Вывод
note scalars: 6
body cleanup
resource scope closed
done

open(path)? делает одну попытку получить файл. using регистрирует неявное закрытие лишь после успешного получения. Действие defer, добавленное позже в теле, выполняется первым, а к строке resource scope closed программа переходит уже после неявного закрытия.

Выбираем владельца времени жизни

СитуацияЧто использовать
Один вызов или блок очистки относится к текущей областиdefer call или defer { ... }
Один File принадлежит одному дочернему блокуusing file = open(path)? { ... }
Получение, чтение или запись могут штатно завершиться неудачейВернуть или разобрать Result; применять ? только в совместимой функции
Программа нарушила контракт среды выполненияСчитать это ошибкой выполнения, а не восстанавливаемой ветвью очистки

Несколько действий defer в одной области выполняются в порядке, обратном регистрации. Очистка также происходит, когда область пересекают return, постфиксный ?, break или continue. Имя в using неизменяемо и видно только внутри тела. Замыкание может сохранить значение File, но неявное закрытие всё равно происходит при выходе из области using: сохранение значения не продлевает жизнь ресурса.

Передача Result — не ошибка выполнения

Если open возвращает Err, очистка ещё не зарегистрирована. Если file.read() возвращает Err, постфиксный ? пересекает действующую область using, поэтому зарегистрированная очистка завершается до выхода ошибки из проверитьЗаметку.

Для ошибки выполнения обещание намеренно уже: она прерывает вычисление, и язык не гарантирует, что после этого будут выполнены все лексические defer или закрытие using. Ошибка внутри самого отложенного действия подчиняется политике записи и сбора ошибок среды выполнения. Она не становится значением, которое можно перехватить, и не заменяет уже возвращаемый Err.

Частое исправление

Не пишите получение файла как File.open(...) и не приписывайте using универсальный протокол ресурсов. Точная функция — open(path), а инструкция using принимает одно простое неизменяемое имя и один File.

Явный вызов close() внутри тела using не отменяет зарегистрированную попытку закрытия. Поведение после закрытия и при повторном закрытии не является переносимым, поэтому обычный код должен оставлять одно закрытие одному владельцу.

Точная граница

Пользовательские протоколы освобождения, одновременное получение нескольких ресурсов, передача владения, асинхронная очистка, очистка при отмене, гарантии для исключений среды и финализация на протяжении жизни модуля не входят в текущее поведение Топаза. Цель генерации обязана сохранить описанное поведение или явно отклонить программу. Этот запуск в интерпретаторе сам по себе не доказывает одинаковую поддержку всеми целями.

Вернитесь к учебному разбору на странице Ошибки и ресурсы, сравните отсутствие и восстанавливаемую ошибку на странице Null, Option, Result и ошибки, а точные операции с файлами найдите в разделе Файлы и ресурсы.