defer, panic, recover

11 вопросов

Механизмы управления потоком выполнения: defer откладывает вызов до конца функции, panic вызывает аварийное завершение, recover перехватывает панику. Порядок выполнения defer - LIFO.

1 Что делает ключевое слово defer? 🟢 Лёгкий
Ответ: B) Откладывает вызов до конца функции

defer f() регистрирует вызов функции, который выполнится при выходе из текущей функции (return, panic). Часто используется для освобождения ресурсов: defer file.Close(), defer mu.Unlock().

Подробнее →
2 В каком порядке выполняются несколько defer? 🟡 Средний
Ответ: B) LIFO (последний вызван - первый выполнен)

Defer'ы складываются в стек (LIFO). Последний зарегистрированный выполняется первым. Это логично: ресурсы освобождаются в порядке, обратном получению.

Подробнее →
3 Что делает recover()? 🟡 Средний
Ответ: B) Перехватывает panic

recover() останавливает распространение паники и возвращает значение, переданное в panic(). Работает только внутри defer-функции. Если паники нет, возвращает nil.

Подробнее →
4 Где нужно вызывать recover()? 🟡 Средний
Ответ: B) В defer-функции

recover() имеет эффект только внутри отложенной (deferred) функции. Вызов recover() в обычном коде всегда возвращает nil. Типичный паттерн: defer func() { if r := recover(); r != nil { log.Println(r) } }().

Подробнее →
5 Что не так с for _, f := range files { r, _ := os.Open(f); defer r.Close() }? 🟡 Средний
Ответ: B) Файлы закроются только при выходе из функции, а не на каждой итерации

defer привязан к функции, не к блоку цикла. Все файлы откроются, но закроются только при выходе из функции. При тысячах файлов - утечка файловых дескрипторов. Решение: вынести тело цикла в отдельную функцию или закрывать явно в конце итерации.

Подробнее →
6 Выполнятся ли deferred функции при вызове os.Exit(0)? 🟡 Средний
Ответ: B) Нет

os.Exit немедленно завершает процесс без выполнения deferred функций. Это отличает его от обычного return из main, при котором defer'ы выполняются. log.Fatal также вызывает os.Exit(1). Используйте os.Exit только когда defer'ы не нужны.

Подробнее →
7 Когда вычисляются аргументы defer? 🔴 Сложный
Ответ: B) В момент вызова defer

Аргументы defer f(x) вычисляются немедленно, а вызов откладывается. Частая ловушка: defer fmt.Println(i) зафиксирует текущее значение i, даже если оно потом изменится. Используйте замыкание для актуального значения.

Подробнее →
8 Можно ли перехватить panic из другой горутины? 🔴 Сложный
Ответ: B) Нет

Каждая горутина имеет свой стек вызовов. recover() работает только в той горутине, где произошла panic. Неперехваченная паника в горутине завершает всю программу.

Подробнее →
9 Что вернёт func f() (r int) { defer func() { r++ }(); return 0 }? 🔴 Сложный
Ответ: B) 1

return 0 устанавливает именованное возвращаемое значение r = 0. Затем выполняется defer, который увеличивает r до 1. Функция возвращает 1. Defer может модифицировать именованные возвращаемые значения после return.

Подробнее →
10 Что вернёт recover() при вызове panic("oops")? 🔴 Сложный
Ответ: B) Строку "oops" (тип any)

recover() возвращает значение типа any, переданное в panic(). При panic("oops") вернётся строка "oops". При panic(42) вернётся int 42. Тип проверяется через type assertion. Без паники recover() вернёт nil.

Подробнее →
11 В чем ловушка: func f() (err error) { if err := validate(); err != nil { return err }; return nil }? 🔴 Сложный
Ответ: A) err в if - новая переменная (short declaration), затеняющая именованный возврат; если позже defer проверяет err, он увидит nil вместо ошибки

Внутри if оператор := создает новую переменную err, затеняющую именованный возврат. Defer, проверяющий err, увидит nil. Решение: = вместо := или другое имя переменной.

Подробнее →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.