Ответ
Оборачивание ошибок (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) }
Основные преимущества:
- Сохранение контекста: Понятно, где и почему произошла ошибка на каждом уровне.
- Упрощение отладки: Полная цепочка ошибок помогает быстро найти корень проблемы.
- Гибкая проверка ошибок: Позволяет надежно реагировать на конкретные типы сбоев.
Ответ 18+ 🔞
А, ну ты смотри, опять про эти ваши обёртки для ошибок. Слушай, это ж как с бутербродом, блядь. Представь: у тебя кусок хлеба — это основная ошибка, os.ErrNotExist, например. А сверху ты намазываешь контекст, как масло с икрой: "не удалось прочитать конфиг". Так вот, раньше-то, сука, мы этот хлеб просто закидывали в блендер, получалась каша-малаша, и понять, что там внутри, было нихуя невозможно.
Проблема-то в чём, ёпта?
Раньше писали так, и всё накрывалось медным тазом:
// Пиздец, а не пример: где моя исходная ошибка? Съела её собака!
if err != nil {
return fmt.Errorf("не удалось прочитать конфиг: %v", err)
}
Вот ты получил такую ошибку, а проверить, был ли это "файл не найден" или "нет прав" — хуй тебе, а не проверка. Всё, пиши пропало. Информация похерена.
А щас, блядь, красота!
Go 1.13 подъехал и говорит: "На, мудила, директиву %w, заворачивай на здоровье".
// О, вот это уже дело! Оригинал ошибки при нас, как в термосе.
if err != nil {
return fmt.Errorf("не удалось прочитать конфиг: %w", err)
}
Теперь ошибка — это как матрёшка, сука. Раскрываешь одну, а внутри ещё сидит, хитрая жопа.
И как с этим чудом работать?
Пакет errors выдал нам два волшебных инструмента, прям как отвёртка и плоскогубцы.
-
errors.Is(err, target): Это чтоб спросить: "Слушай, а в этой цепочке случайно не затесалсяos.ErrNotExist?" Идеально, когда тебе важно значение ошибки.if errors.Is(err, os.ErrNotExist) { fmt.Println("Файлика-то нет, ёбта! Давай по дефолту.") } -
errors.As(err, target): А это уже поинтереснее. Тут ты спрашиваешь: "А нет ли тут ошибки типа*fs.PathError? Если есть — дай-ка я на неё посмотрю поближе, полюбопытствую, что у неё в полях записано".targetдолжен быть указателем, не забудь, а то опозоришься.var pathError *fs.PathError if errors.As(err, &pathError) { fmt.Printf("Вот же ж блядь! Проблема с путём: %sn", pathError.Path) }
И что в сухом остатке, спросишь ты?
- Контекст не теряется: Каждый уровень добавляет свои "пять копеек", и в логе видна вся история, как на ладони. Не надо гадать на кофейной гуще.
- Отладка — одно удовольствие: Цепочка ведёт прямиком к корню зла. Никаких "ой, а откуда это вообще взялось?".
- Гибкая реакция: Можешь чётко ловить конкретные сценарии и обрабатывать их как надо, а не одной общей молитвой на все случаи жизни.
В общем, вещь, блядь, полезная. Не игнорируй, а то будешь потом как Герасим — "Муму-муму" говорить, а помочь ничем не сможешь.