Как в Go обрабатывают ошибки и зачем нужны errors.Is, errors.As и %w?
- Почему в Go нет исключений?
- Как обернуть ошибку в Go, сохранив исходную?
Ошибка — обычное значение типа error, которое функция возвращает последним: if err != nil { return ... }. Оборачивают с контекстом через fmt.Errorf("...: %w", err). Проверяют errors.Is (совпадение с конкретной ошибкой в цепочке) и errors.As (найти ошибку нужного типа).
- Сравнение err == ErrNotFound не работает для обёрнутых — только errors.Is
- Сигнальные ошибки: var ErrNotFound = errors.New("not found")
- Свой тип ошибки — для данных (код, поле)
А ещё errors.Join (1.20) — объединить несколько ошибок
Подробно
Почему значения, а не исключения. Путь ошибки виден в коде явно: каждая функция, которая может упасть, это показывает, а вызывающий решает, что делать. Нет скрытых переходов через несколько уровней стека. Цена — многословность.
Оборачивание. %w сохраняет исходную ошибку внутри новой; цепочка раскручивается errors.Unwrap. Сообщение получается вида «repo.Get 42: dial tcp: connection refused» — контекст каждого уровня. %v вместо %w добавит текст, но разорвёт цепочку для Is и As.
Правила:
- обрабатывать ошибку один раз: либо вернуть с контекстом, либо залогировать, но не оба;
- не игнорировать (
_ = f()) без явной причины; - не сравнивать по тексту
err.Error(); - сигнальные ошибки — часть API пакета, менять их нельзя.
Пример
var ErrNotFound = errors.New("not found")
func (r *Repo) Get(id int) (*User, error) {
u, err := r.db.query(id)
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("repo.Get %d: %w", id, err)
}
return u, nil
}
if errors.Is(err, ErrNotFound) { http.Error(w, "нет", 404) }
var ve *ValidationError
if errors.As(err, &ve) { log.Println(ve.Field) }Что хотят услышать
- Ошибки как значения.
- Оборачивание через %w.
- errors.Is и errors.As.
- Правила обработки.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Ошибки в Go обрабатывают исключениями try/catch
- ✗err == ErrNotFound работает и для ошибок, обёрнутых через fmt.Errorf с %w
- ✗%v сохраняет цепочку для errors.Is так же, как %w
- ✓Ошибка — значение; оборачивают через %w, проверяют errors.Is/As
Что спросят дальше
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.