Ответ
В Go отсутствует традиционный механизм исключений (try-catch-finally
), как в Java или C++. Вместо этого используется подход, основанный на явной обработке ошибок как значений.
1. error
— основной механизм
Идиоматический способ обработки ожидаемых ошибок — это возврат значения типа error
последним из функции. error
— это встроенный интерфейс:
type error interface {
Error() string
}
Если функция выполнилась успешно, она возвращает nil
в качестве ошибки. В противном случае — объект ошибки.
import "os"
func readFile(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
// Ошибка обрабатывается сразу на месте вызова
return nil, err
}
return data, nil
}
Современные практики: Оборачивание ошибок (Error Wrapping)
Начиная с Go 1.13, появилась возможность оборачивать ошибки, чтобы сохранить контекст. Это делается с помощью fmt.Errorf
и директивы %w
.
import (
"fmt"
"os"
)
func processFile(path string) error {
data, err := os.ReadFile(path)
if err != nil {
// Оборачиваем исходную ошибку, добавляя контекст
return fmt.Errorf("failed to process file: %w", err)
}
// ...
return nil
}
Для проверки цепочки ошибок используются функции errors.Is()
(проверка на конкретное значение ошибки) и errors.As()
(проверка на соответствие типа ошибки).
2. panic
— для исключительных ситуаций
panic
— это встроенная функция, которая останавливает обычный поток выполнения и начинает "панику". Программа завершается, если паника не будет обработана.
Когда использовать panic
?
- При возникновении действительно невосстановимой ошибки, когда программа не может продолжать безопасное выполнение (например, не удалось инициализировать критически важный компонент при старте).
- В коде, который не должен падать (например, ошибки программиста, такие как выход за пределы массива).
if configPath == "" {
panic("Critical: configuration path is not set")
}
3. recover
— для перехвата паники
recover
— это встроенная функция, которая позволяет восстановить контроль над программой после паники. recover
работает только внутри defer
-функций.
Её основное применение — предотвратить падение всего приложения из-за ошибки в одной из подпрограмм (например, в обработчике HTTP-запроса, чтобы сервер не упал из-за одного сбойного запроса).
func safeHandler() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
// Здесь можно залогировать ошибку и отдать корректный ответ клиенту
}
}()
// Код, который может вызвать панику
potentiallyPanicFunction()
}
Важно: panic/recover
не является заменой error
. Это механизм для обработки непредвиденных, катастрофических сбоев, а не для обычной логики обработки ошибок.