Как в Go обработать панику с помощью defer?

Ответ

Да, обработка паники с помощью defer и recover — это основной и идиоматичный механизм в Go для перехвата и обработки критических ошибок.

Механизм работает так:

  1. defer гарантирует, что вызов функции будет выполнен перед выходом из текущей функции, независимо от того, завершается она нормально или из-за паники.
  2. recover() — это встроенная функция, которая останавливает панику и возвращает значение, с которым была вызвана panic. Если паники не было, recover() возвращает nil.
package main

import "fmt"

func main() {
    fmt.Println("Начало выполнения main")
    safeCall()
    fmt.Println("main успешно завершена")
}

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

    fmt.Println("Вызов опасной функции...")
    panickingFunction()
    fmt.Println("Этот код не будет выполнен")
}

func panickingFunction() {
    panic("произошла критическая ошибка")
}

Важные правила:

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

Этот механизм позволяет «превратить» панику в обычную ошибку, предотвращая аварийное завершение всей программы и позволяя функции-обертке обработать сбой более грациозно.