Ответ
В Go панику можно перехватить и обработать с помощью встроенной функции recover()
. Ключевое правило: recover()
работает только внутри отложенной функции (defer
).
Если паника не обработана, выполнение программы немедленно прекращается.
Механизм работы
- Вызывается
panic()
с некоторым значением (обычно строкой или ошибкой). - Выполнение текущей функции останавливается.
- Начинается выполнение
defer
-функций в LIFO-порядке. - Если в одной из
defer
-функций вызываетсяrecover()
, она возвращает значение, переданное вpanic()
. Выполнение программы возобновляется с точки выхода из функции, где произошла паника.
Классический пример — защита HTTP-обработчика:
func safeHandler(w http.ResponseWriter, r *http.Request) {
// defer-функция для перехвата паники
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic: %vn%s", r, debug.Stack())
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
// Код, который может вызвать панику
potentiallyPanicFunction()
fmt.Fprintln(w, "Success")
}
func potentiallyPanicFunction() {
panic("something went terribly wrong!")
}
Ключевые моменты:
- Паника в горутине: Паника в любой горутине (кроме
main
) приводит к завершению всей программы, если она не обработана с помощьюrecover
внутри этой же горутины. panic
vserror
: В идиоматическом Go панику следует использовать только для действительно исключительных ситуаций, указывающих на ошибку в программе (например, выход за пределы массива), а не для ожидаемых ошибок (отсутствие файла, сетевые проблемы). Для обработки ожидаемых ошибок всегда используйте типerror
.