Что означает ключевое слово defer в Go?

Когда выполняется отложенный вызов, почему важен порядок LIFO и почему defer не является безусловной гарантией очистки при любом завершении процесса.

Короткий ответ

Что ответить на собеседовании

defer откладывает вызов до выхода из окружающей функции. Функция и аргументы вызова вычисляются сразу, а отложенные вызовы выполняются в обратном порядке. Механизм удобен для освобождения ресурсов; он работает при обычном возврате и раскрутке panic, но не при os.Exit или принудительном завершении процесса.

Подробный разбор

Ответ с пояснениями

defer регистрирует вызов, который выполнится перед возвратом окружающей функции. Это не выход из ближайшего блока или итерации цикла. Несколько вызовов выполняются в порядке LIFO: последним зарегистрирован — первым выполнен. Правила определены в спецификации Go.

func example() {
    value := 1
    defer fmt.Println(value)
    value = 2
    fmt.Println(value)
}

Функция напечатает сначала 2, затем 1: аргумент отложенного вызова вычислен при выполнении defer. Замыкание, читающее переменную позднее, может дать другой результат.

Обычный сценарий — открыть файл, проверить ошибку и только после успешного открытия зарегистрировать defer file.Close(). В цикле внутри долгоживущей функции такие закрытия накапливаются; при необходимости ресурс обрабатывают в отдельной функции.

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

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку