Следует ли использовать% s или% v для форматирования ошибок?
TL; DR; Ни то, ни другое. Используйте %w
в 99,99% случаев. В остальных 0,001% случаев %v
и %s
, вероятно, "должны" вести себя одинаково, за исключением случаев, когда значение ошибки равно nil
, но нет никаких гарантий. Более дружественный вывод %v
для nil
ошибок может быть причиной для предпочтения %v
(см. Ниже).
Теперь для деталей:
Используйте %w
вместо %v
или %s
:
Начиная с Go 1.13 (или ранее, если вы используете golang .org / x / xerrors ), вы можете использовать только глагол %w
для значений error
, которые обертывают ошибку так, чтобы впоследствии ее можно было развернуть с помощью errors.Unwrap
, и чтобы ее можно было рассмотреть с errors.Is
и errors.As
.
Единственные случаи, когда это неуместно :
- Вы должны поддерживать более старую версию Go, и
xerrors
не вариант. - Вы хотите создать уникальную ошибку, а не обернуть существующий. Это может быть целесообразно, например, если вы получаете ошибку
Not found
из своей базы данных при поиске пользователя и хотите преобразовать ее в Unauthorized
ответ. В таком случае редко можно использовать исходное значение ошибки с любым глаголом форматирования, однако.
Хорошо, так что насчет %v
и * 1048? *?
Подробная информация о том, как реализованы %s
и %v
, доступна в документации . Я выделил части, относящиеся к вашему вопросу.
Если операнд является отражением. Значение, операнд заменяется конкретным значением, которое он содержит, и печать продолжается со следующим правилом.
Если операнд реализует интерфейс Formatter, он будет вызван. Formatter обеспечивает точный контроль форматирования.
Если глагол% v используется с флагом # (% # v) и операнд реализует интерфейс GoStringer, он будет вызван.
Если формат ( что неявно% v для Println et c.) допустимо для строки (% s% q% v% x% X), применяются следующие два правила :
Если в операнде реализован интерфейс ошибок, будет вызван метод Error для преобразования объекта в строку, которая затем будет отформатирована в соответствии с требованиями глагола (если есть).
Если операнд реализует метод String () string, этот метод будет Он вызвал для преобразования объекта в строку, которая затем будет отформатирована в соответствии с требованиями глагола (если есть).
Подводя итог, fmt.*f
функции будут:
- Искать метод
Format()
, и если он существует, они будут его вызывать. - Искать метод
Error()
, и если он существует, они вызовут его. - Найдите метод
String()
, и, если он существует, вызовите его. - Используйте форматирование по умолчанию.
Так что в На практике это означает, что %s
и %v
идентичны, за исключением случаев, когда существует метод Format()
для типа ошибки (или когда ошибка nil
). Когда у ошибки есть метод Format()
, можно надеяться, что он выдаст тот же результат с %s
, %v
и err.Error()
, но, поскольку это зависит от реализации ошибки, нет гарантии и, следовательно, никакого «правильного ответа» здесь.
И, наконец, если ваш тип ошибки поддерживает вариант глагола %+v
, то вам, конечно, нужно будет это использовать, если вы хотите получить подробный вывод .
nil
значения
Хотя редко (намеренно) вызывать fmt.*f
при ошибке nil
, поведение между %s
и %v
:
%s: %!s(<nil>)
%v: <nil>
ссылка на игровую площадку