Материал проходит вычитку — возможны неточности.
Урок 52 из 118

defer: выполнить при выходе

Импорт каталога потихоньку съедал дескрипторы: файлы открывались, а закрытие терялось где-то в ветках. На больших пачках сервис упирался в лимит операционной системы. Миша привязал закрытие к самому открытию.

Главная мысль

defer — «выполни этот вызов, когда функция будет выходить», на любом пути: обычный return, return из середины или паника.

Классический пример — закрыть файл сразу после открытия, чтобы не таскать Close по всем веткам кода.

Закрытие файла

func readConfig(path string) ([]byte, error) {
    f, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer f.Close()
    return io.ReadAll(f)
}

Без defer пришлось бы писать f.Close перед return io.ReadAll(f). Пока веток одна, разницы нет, но стоит добавить проверку ошибки посередине — и Close надо не забыть вставить в каждую новую точку выхода. defer ставит очистку рядом с инициализацией и гарантирует, что она выполнится, откуда бы функция ни вышла. Именно так Миша заткнул течь дескрипторов в импорте.

Порядок — как стек

Отложенные вызовы выполняются в обратном порядке объявления, последний объявленный — первым.

Go

Для вложенных ресурсов это удобно: открыл файл, потом взял блокировку — при выходе сначала снимется блокировка, потом закроется файл, в правильном порядке.

В следующем уроке

Вы узнаете:

  • как с Go 1.14 компилятор оптимизирует простые defer
  • почему очистка с defer срабатывает даже при панике
Задание · вопросы

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

Вопрос 1 из 3

defer fmt.Println("первый"); defer fmt.Println("второй"); defer fmt.Println("третий"). Какой порядок вывода?

Вопрос 2 из 3

Зачем нужен defer?

Вопрос 3 из 3

Где идиоматично ставить defer?

Итоги

defer — это про гарантию очистки. Увидел пару «взял ресурс — надо вернуть» — ставь defer: mu.Lock() рядом с defer mu.Unlock(), os.Open рядом с defer f.Close(). Это идиома, по которой Go-код узнаётся с одного взгляда, и она убирает целый класс багов с утечками и забытыми ветками.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки