Почему `recover()` следует использовать именно в отложенной функции (`defer`) и какова его роль?

Ответ

Основная задача recover() — перехватить панику, чтобы предотвратить аварийное завершение программы и выполнить код для graceful shutdown или обработки ошибки.

recover() эффективно работает только при вызове внутри отложенной функции (defer), потому что:

  1. Когда возникает паника, нормальное выполнение функции немедленно прекращается.
  2. Исполнение переходит к выполнению defer функций, которые были отложены в этой горутине.
  3. Только на этом этапе recover() может "поймать" панику. Если вызвать recover() вне defer, он просто вернет nil, так как в момент его вызова паники еще (или уже) нет.

Пример корректного использования:

func safeFunc() {
    defer func() {
        // recover() перехватывает значение, переданное в panic()
        if r := recover(); r != nil {
            fmt.Println("Перехвачена паника:", r)
        }
    }()

    fmt.Println("Начало выполнения safeFunc")
    // Симуляция критической ошибки
    panic("что-то пошло не так")
    // Этот код никогда не выполнится
    fmt.Println("Завершение выполнения safeFunc")
}

Ключевые моменты:

  • Место вызова: recover() должен быть вызван непосредственно из defer функции. Вызов из функции, которую вызывает defer, не сработает.
  • Возвращаемое значение: Возвращает значение, переданное в panic(), или nil, если паники не было.
  • Продолжение выполнения: После успешного recover() паника прекращается, и выполнение продолжается со следующего оператора после вызова функции, в которой произошла паника. Сама запаниковавшая функция не возобновляет свою работу.