Часто используемый контракт для функций, возвращающих значение ошибки типа интерфейса, заключается в том, что вызывающая сторона не должна заранее ничего знать о состоянии других значений, возвращаемых этим вызовом, без предварительной проверки на наличие ошибки.
В большинстве случаев значения ошибок, возвращаемые функциями, должны быть непрозрачны для вызывающей стороны.
То есть тест, в котором ошибка равна нулю, показывает, был ли вызов успешным или неудачным, и это все, что нужно.
картина отсюда В небольшом количестве случаев, обычно связанных с взаимодействием с внешним миром, например сетевой активностью, вызывающей стороне требуется изучить природу ошибки, чтобы решить, целесообразно ли повторить операцию.
Общее требование к авторам пакетов — возвращать ошибки известного общедоступного типа, чтобы вызывающая сторона могла использовать утверждение типа и подробно их изучить.
Я считаю, что такая практика приводит к ряду нежелательных результатов:
- Открытые типы ошибок увеличивают «зону контакта» с API пакета.
- Новые реализации должны возвращать только те типы, которые указаны в объявлении интерфейса, даже если они не подходят.
- Тип ошибки, добавленный в код, не может быть изменен или признан устаревшим без нарушения совместимости, что делает API хрупким.
Подтвердите ожидаемое поведение, а не тип ошибки
Не указывайте, что значение ошибки относится к определенному типу, а укажите, что значение реализует определенное поведение.Это предложение соответствует природе неявных интерфейсов Go, а не является [подтипом] природы языков, основанных на наследовании.
Рассмотрим этот пример:
Вызывающий может использовать isTimeout(), чтобы определить, произошла ли ошибка из-за тайм-аута, реализовав интерфейс тайм-аута, а затем подтвердить, произошла ли ошибка из-за тайм-аута - и все это без каких-либо знаний о типе или исходных значениях ошибки источника.func isTimeout(err error) bool { type timeout interface { Timeout() bool } te, ok := err.(timeout) return ok && te.Timeout() }
Этот метод позволяет оборачивать ошибки, обычно с помощью библиотек, которые добавляют пояснения к пути ошибки; при условии, что обернутые типы ошибок также реализуют интерфейсы ошибок, которые они обертывают. Это может показаться непреодолимой проблемой, но на практике существует довольно много распространенных методов интерфейса, поэтому Timeout() bool и Temporary() bool охватывают большой набор вариантов использования.
Окончательно
Подтвердите ожидаемое поведение, а не тип ошибкиДля авторов пакетов
Если ваш пакет генерирует временные ошибки, убедитесь, что вы возвращаете типы ошибок, реализующие соответствующие методы интерфейса.Если вы переносите значения ошибок в выходные данные, убедитесь, что ваши оболочки поддерживают интерфейс(ы), с помощью которых реализуется исходное значение ошибки.
Для пользователей пакета
Если вам нужно проверить наличие ошибки, используйте интерфейсы для проверки ожидаемого поведения, а не типа ошибки.Не спрашивайте авторов пакетов о типах открытых ошибок; попросите их привести свои типы в соответствие с общими интерфейсами, указав соответствующие методы Timeout() или Temporary().
об авторе
Автор этой статьи, Дэйв Чини , является автором многих популярных пакетов Go, таких как https://github.com/pkg/errors И https://github.com/davecheney/httpstat .
От переводчика
Хоть оригинал статьи и датирован концом 2014 года, мне кажется, она не потеряла своей актуальности.Описанный подход встречается в немногих пакетах, остальные используют обычный подход к ошибкам.
Правки в текст для улучшения понятности материала приветствуются! Теги: #Go #golang #обработка ошибок #Обработка ошибок
-
Mail.ru Group Продала Фотохостинг Radikal
19 Oct, 24 -
Тестирование Асинхронного Кода
19 Oct, 24 -
Официальный Репозиторий Плагинов Mootools
19 Oct, 24 -
Hyperflex — Две Новые Флэш-Системы От Cisco
19 Oct, 24 -
Chaos Construction 2010. Мои Впечатления
19 Oct, 24