Ответ
Это механизм Go для обработки исключительных, непредвиденных ситуаций, которые делают дальнейшее выполнение программы невозможным в текущем контексте.
-
panic— это встроенная функция, которая останавливает обычное выполнение текущей горутины. Когда функция вызываетpanic, её выполнение прекращается, все отложенные (defer) вызовы в этой функции выполняются, после чего функция возвращает управление вызвавшей её функции, где происходит то же самое. Процесс продолжается вверх по стеку вызовов, пока программа не завершится аварийно. -
defer— это ключевое слово, которое откладывает выполнение вызова функции до тех пор, пока содержащая её функция не завершит свое выполнение (либо черезreturn, либо из-заpanic). Отложенные вызовы выполняются в порядке LIFO (Last-In, First-Out) — последняя отложенная функция выполнится первой. -
recover— это встроенная функция, которая позволяет перехватить управление горутиной, находящейся в состоянии паники.recoverполезна только внутриdefer-функций. Если текущая горутина не паникует, вызовrecoverвернетnil. Если же горутина паникует, вызовrecoverперехватит значение, переданное вpanic, и восстановит нормальное выполнение.
Пример:
func main() {
fmt.Println("Start")
safeDivide(10, 0)
fmt.Println("End")
}
func safeDivide(a, b int) {
defer func() {
// recover работает только внутри defer
if r := recover(); r != nil {
fmt.Printf("Перехвачена паника: %vn", r)
}
}()
result := a / b // Эта строка вызовет панику
fmt.Printf("Результат: %dn", result) // Эта строка не выполнится
}
Вывод:
Start
Перехвачена паника: runtime error: integer divide by zero
End
Когда использовать:
Основное правило — не использовать panic для обычной обработки ошибок. Для этого в Go есть явный возврат error.
Допустимые случаи использования panic/recover:
- Предотвращение падения всего сервера. Например, в веб-сервере одна горутина, обрабатывающая HTTP-запрос, может запаниковать из-за непредвиденной ошибки. С помощью
recoverвdeferможно перехватить эту панику, записать лог, отдать клиенту ошибку 500, но при этом сам сервер продолжит работать и обслуживать другие запросы. - Ошибки в программе, которые не должны происходить. Например, если программа достигает состояния, которое считается невозможным (например,
caseвswitch, который никогда не должен сработать). Это сигнал о серьезной ошибке в логике программиста.