В чем разница между errors.Is и errors.As в Go?
Что проверяют
Умеете ли вы работать с обёрнутыми ошибками. После версии 1.13 сравнение через == и приведение типом напрямую считаются ошибкой, и это ровно то, что здесь смотрят.
Как отвечать
Обе функции разворачивают цепочку обёрток, созданную через fmt.Errorf("...: %w", err), но отвечают на разные вопросы.
errors.Is(err, target)отвечает «это та самая ошибка?». Сравнивает со значением-часовым:io.EOF,sql.ErrNoRows,context.DeadlineExceeded, вашаvar ErrNotFound = errors.New(...);errors.As(err, &target)отвечает «есть ли в цепочке ошибка такого типа?». Если есть, записывает её в переданную переменную, и дальше можно прочитать поля: код, поле, номер строки.
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrNotFound
}
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
return nil, ErrDuplicate // нарушение уникальности
}Отсюда правило: значение сравнивается через Is, тип с полезной начинкой достаётся через As.
Важные детали: As принимает именно указатель на переменную нужного типа, иначе паника; обёртка обязана использовать %w, а не %v, иначе цепочка обрывается и обе функции вернут false; свой тип ошибки может определить методы Is или Unwrap, чтобы участвовать в этих проверках; начиная с версии 1.20 можно обернуть несколько ошибок сразу через errors.Join, и Is найдёт любую из них.
Где спотыкаются
Сравнивают ошибки через == и ломаются на первой же обёртке.
Пишут %v вместо %w при оборачивании и теряют возможность проверки.
Сравнивают ошибки по тексту через strings.Contains(err.Error(), "not found"). Работает до первой правки формулировки.