Что такое `panic` в Go? В чем его отличие от ошибок (`error`) и когда его следует использовать?

Ответ

panic в Go — это встроенная функция, которая вызывает исключительную ситуацию, приводящую к остановке нормального выполнения программы. Это механизм для обработки непредвиденных и невосстановимых ошибок времени выполнения.

Ключевое отличие от error:

  • error: Используется для ожидаемых ошибок, которые являются частью нормальной работы функции (например, файл не найден, ошибка сети). Ошибки в Go — это значения, которые функция возвращает, и вызывающий код должен их обработать.
  • panic: Используется для критических, невосстановимых ошибок, при которых дальнейшее выполнение программы небезопасно или бессмысленно (например, обращение по nil-указателю, выход за пределы массива). Это сигнализирует об ошибке программиста.

Как работает panic:

  1. Выполнение текущей функции немедленно прекращается.
  2. Начинается «раскрутка стека» (stack unwinding) горутины: выполняются все отложенные вызовы (defer).
  3. Если panic не будет перехвачен с помощью recover, программа завершится с выводом сообщения о панике и стека вызовов.

Перехват panic с помощью recover

Функция recover позволяет перехватить панику и возобновить нормальное выполнение. Важно: recover работает только внутри отложенной (defer) функции.

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Перехватили панику:", r)
        }
    }()

    fmt.Println("Вызываем функцию, которая паникует")
    riskyFunction("что-то пошло не так")
    fmt.Println("Эта строка не выполнится")
}

func riskyFunction(message string) {
    panic(message)
}

Когда использовать panic:

  • Внутри пакета main: Если программа не может запуститься или продолжать работу из-за критической проблемы (например, не удалось прочитать обязательный конфиг).
  • При ошибках программиста: Когда состояние программы становится некорректным из-за логической ошибки, которую невозможно штатно обработать (например, бесконечная рекурсия).

Основное правило: Не используйте panic для обработки обычных ошибок в библиотечном коде. Библиотеки должны возвращать error, предоставляя вызывающему коду решать, как на них реагировать.