Каковы условия для успешного перехвата паники с помощью `recover`?

Ответ

Функция recover может перехватить панику только при соблюдении двух ключевых условий:

  1. Вызов внутри defer: recover должен вызываться непосредственно внутри отложенной (deferred) функции. Если вызвать его в любом другом месте, он вернет nil и не будет иметь никакого эффекта.
  2. Та же горутина: recover может перехватить панику только в той же горутине, в которой она произошла. Паника в одной горутине не может быть перехвачена в другой.
package main

import "fmt"

func main() {
    // Пример правильного использования
    safeCall()

    fmt.Println("Программа продолжает работу после перехвата паники.")

    // Паника в main не будет перехвачена, т.к. нет defer с recover
    // panic("Эта паника завершит программу")
}

func safeCall() {
    // 1. Функция defer будет выполнена при выходе из safeCall, в том числе при панике
    defer func() {
        // 2. recover перехватывает значение, переданное в panic
        if r := recover(); r != nil {
            fmt.Printf("Паника перехвачена: %vn", r)
        }
    }()

    fmt.Println("Вызываем функцию, которая может запаниковать...")
    causePanic()
    fmt.Println("Эта строка не будет выполнена.")
}

func causePanic() {
    panic("произошла управляемая паника")
}

Важные моменты:

  • recover возвращает значение, переданное в panic. Если паники не было, recover вернет nil.
  • recover не может перехватить некоторые фатальные ошибки времени выполнения (например, out of memory), которые приводят к немедленному завершению программы.