Вопрос с собеседования · Go

Как работает defer и в каком порядке выполняются отложенные вызовы?

JuniorОсновы языка
Ещё спрашивают так:
  • Когда вычисляются аргументы defer?
  • Можно ли изменить возвращаемое значение в defer?
Коротко

defer откладывает вызов до выхода из функции — при обычном return и при panic. Отложенные вызовы выполняются в порядке LIFO (последний — первым). Аргументы вычисляются сразу в момент defer, а не при выполнении. Через именованные результаты defer может изменить возвращаемое значение.

  • Типичное применение: f.Close(), mu.Unlock(), recover
  • defer в цикле копит вызовы до конца функции — ресурсы держатся долго
  • Ошибку Close при записи файла не стоит игнорировать

А ещё Стоимость defer в Go 1.14+ почти нулевая

Подробно

Вычисление аргументов. defer fmt.Println(x) запоминает значение x в момент выполнения строки defer. Если нужна актуальная переменная — замыкание: defer func() { fmt.Println(x) }().

defer в цикле. Открывая тысячу файлов в цикле с defer f.Close(), все они закроются только в конце функции — исчерпание дескрипторов. Решение — вынести тело цикла в отдельную функцию.

Возвращаемое значение. return x сначала присваивает результат, затем выполняет отложенные вызовы. Если результат именованный, defer может его прочитать и изменить — так обрабатывают ошибку закрытия и превращают panic в error.

Пример

func read(path string) (err error) {
    f, err := os.Open(path)
    if err != nil { return err }
    defer func() {
        if cerr := f.Close(); cerr != nil && err == nil {
            err = cerr                 // меняем именованный результат
        }
    }()
    ...
}

for i := 0; i < 3; i++ {
    defer fmt.Println(i)   // напечатает 2, 1, 0
}

Что хотят услышать

  • Когда выполняется и порядок LIFO.
  • Момент вычисления аргументов.
  • Ловушка defer в цикле.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗Отложенные вызовы выполняются в порядке объявления
  • ✓LIFO при выходе из функции, даже при panic; аргументы вычисляются сразу
  • ✗Аргументы defer вычисляются в момент самого вызова
  • ✗defer не выполняется при panic

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

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

Разбор собеседования