Ответ
Оборачивание ошибок (error wrapping) — это механизм, который позволяет создавать новую ошибку, сохраняя при этом исходную (оригинальную) ошибку. Это делается для добавления контекста к ошибке по мере её продвижения вверх по стеку вызовов.
Проблема, которую это решает:
Без оборачивания, при возврате ошибки из функции, мы часто теряем исходную информацию. Например:
// Плохой пример: теряется исходная ошибка os.ErrNotExist
if err != nil {
return fmt.Errorf("не удалось прочитать конфиг: %v", err)
}
В этом случае мы больше не можем программно проверить, была ли исходная проблема в том, что файл не найден (os.ErrNotExist
).
Решение с помощью %w
:
Начиная с Go 1.13, для оборачивания используется директива %w
в функции fmt.Errorf
.
// Хороший пример: исходная ошибка сохраняется
if err != nil {
return fmt.Errorf("не удалось прочитать конфиг: %w", err)
}
Как работать с обёрнутыми ошибками:
Пакет errors
предоставляет две функции для инспекции цепочки ошибок:
-
errors.Is(err, target)
: Проверяет, есть ли в цепочке ошибокerr
ошибка, эквивалентнаяtarget
. Идеально для проверки на конкретные значения ошибок (например,io.EOF
,sql.ErrNoRows
).if errors.Is(err, os.ErrNotExist) { fmt.Println("Файл конфигурации не найден, используем значения по умолчанию.") }
-
errors.As(err, target)
: Проверяет, есть ли в цепочке ошибка, которую можно присвоить переменнойtarget
(которая должна быть указателем на тип ошибки). Используется для получения доступа к полям конкретного типа ошибки.var pathError *fs.PathError if errors.As(err, &pathError) { fmt.Printf("Ошибка связана с путем: %sn", pathError.Path) }
Основные преимущества:
- Сохранение контекста: Понятно, где и почему произошла ошибка на каждом уровне.
- Упрощение отладки: Полная цепочка ошибок помогает быстро найти корень проблемы.
- Гибкая проверка ошибок: Позволяет надежно реагировать на конкретные типы сбоев.