panic(nil) и re-panic †
Старая библиотека разбора паниковала по-особому: пустым значением, и перехват не мог отличить падение от спокойного выхода. Миша не стал глотать чужую панику и пробросил её дальше по стеку.
panic(nil) с Go 1.21 отличим от «паники не было», а необработанную чужую панику бросают дальше через re-panic.
Panic(nil)
До Go 1.21 recover возвращал nil и когда паники нет, и при panic(nil) — отличить одно от другого было невозможно. С Go 1.21 panic(nil) передаёт в recover не nil, а *runtime.PanicNilError. Теперь проверка recover != nil честно означает «паника была».
Что здесь показано
- Стек — локальные переменные функции.
i = 3— значение;p = ptr → 10— указатель на значение;b = "hello"— срез (заголовок: указатель + длина + ёмкость). - Куча — данные, на которые ссылаются переменные:
rodata— байты строки-литерала (в бинарнике),данные N Б— бэкинг-массив слайса,строка— динамическая строка. - Горутины — лёгкие потоки Go: статус (running/runnable/waiting…), функция, в которой каждая сейчас находится, размер стека (растёт по мере работы) и пометка «из main» — горутина запущена из твоего кода.
- GC — сборщик мусора: фаза (off/mark) и число завершённых циклов.
Re-panic
Иногда поймать панику — не значит её обработать. Если defer понял, что эта паника не его, он обязан бросить её дальше:
defer func() {
if r := recover(); r != nil {
if _, ok := r.(myPanic); !ok {
panic(r) // re-panic
}
}
}()
Re-panic продолжает разматывание, как будто recover не было.
Где recover действительно живёт
На границах, где паника не должна убить процесс. Классическое место — HTTP-сервер: стандартный net/http перехватывает панику на уровне соединения (в conn.serve), чтобы один упавший запрос не обрушил весь сервис. Или граница между чужим кодом и твоим, когда библиотека паникует, а тебе нужна ошибка.
recover не для управления потоком: превращать панику в механизм передачи ошибок между уровнями — медленно, неудобно и сбивает с толку. Паника — аварийный тормоз, а не ещё один способ вернуть ошибку.
Вы узнаете:
- как
net/httpреализует перехват паники в обработчиках - чем
os.Exitотличается от паники
Проверьте себя
panic(nil) на Go 1.21+. Что возвращает recover?
Паника в HTTP-обработчике net/http. Что произойдёт с сервисом?
В defer поймана чужая паника, которую ты не обрабатываешь. Что делать?
правильных ответов
panic(nil) теперь отличим; чужую панику не глотают — бросают дальше. recover оправдан на границах, где падение одного запроса не должно рушить сервис.
10 000 ₽ · 60 минут · онлайн