Как работает функция `recover` в Go и каковы правила её использования?

Ответ

recover — это встроенная функция в Go, предназначенная для перехвата паники (panic) и восстановления нормального выполнения горутины.

Ключевое правило: recover работает только внутри функции, отложенной с помощью defer. Если recover вызывается вне defer или в горутине, где не было паники, она вернет nil и не будет иметь никакого эффекта.

Пример работы:

package main

import "fmt"

func main() {
    // defer гарантирует, что эта функция выполнится перед выходом из main,
    // даже если произойдет паника.
    defer func() {
        // recover() перехватывает значение, переданное в panic()
        if r := recover(); r != nil {
            fmt.Println("Восстановлено после паники:", r)
        }
    }()

    fmt.Println("Вызываем функцию, которая паникует.")
    causePanic()
    // Эта строка никогда не выполнится, так как управление перейдет к defer.
    fmt.Println("Функция main завершается штатно.")
}

func causePanic() {
    fmt.Println("Сейчас будет паника!")
    panic("произошла критическая ошибка")
}

// Вывод:
// Вызываем функцию, которая паникует.
// Сейчас будет паника!
// Восстановлено после паники: произошла критическая ошибка

Когда следует использовать recover?

Использование panic/recover для обычной обработки ошибок считается плохой практикой. Для этого в Go существует механизм возврата error.

Основные сценарии для recover:


  1. Предотвращение падения всего приложения: В серверах (например, HTTP-сервер) recover используется в defer на верхнем уровне горутины, обрабатывающей запрос. Это позволяет изолировать панику: одна неудачная обработка запроса не приведет к падению всего сервера.



  2. В библиотеках: Чтобы паника внутри библиотеки не "протекла" наружу и не обрушила приложение, которое её использует. В этом случае панику можно перехватить и вернуть как обычное значение error.