Ответ 1
Попробуйте
err.Error() == "Token is expired"
Или создайте собственную ошибку, выполнив интерфейс ошибки.
У меня есть значение ошибки, которое при печати на консоли дает мне Token is expired
Как я могу сравнить это с определенным значением ошибки? Я попробовал это, но это не сработало:
if err == errors.New("Token is expired") {
log.Printf("Unauthorised: %s\n", err)
}
Попробуйте
err.Error() == "Token is expired"
Или создайте собственную ошибку, выполнив интерфейс ошибки.
Этот ответ для Go 1.12 и более ранних версий.
Определите значение ошибки в библиотеке
package fruits
var NoMorePumpkins = errors.New("No more pumpkins")
Не создавайте ошибок с errors.New
где-либо в коде, но возвращайте предопределенное значение всякий раз, когда возникает ошибка, и тогда вы можете сделать следующее:
package shop
if err == fruits.NoMorePumpkins {
...
}
См. io
об ошибках пакета для справки.
Это можно улучшить, добавив методы, чтобы скрыть реализацию проверки и сделать клиентский код более защищенным от изменений в пакете fruits
.
package fruits
func IsNoMorePumpkins(err error) bool {
return err == NoMorePumpkins
}
Смотрите os
ошибки пакета для справки.
Для пакетов идиоматично экспортировать переменные ошибок, которые они используют, чтобы другие могли сравнивать их.
Например, если ошибка возникла из пакета с именем myPkg и была определена как:
var ErrTokenExpired error = errors.New("Token is expired")
Вы можете сравнить ошибки непосредственно как:
if err == myPkg.ErrTokenExpired {
log.Printf("Unauthorised: %s\n", err)
}
Если ошибки происходят из стороннего пакета и в нем не используются экспортированные переменные ошибок, то вы можете просто сравнить со строкой, полученной из err.Error(), но будьте осторожны с этим подходом, поскольку изменение строки ошибки может не будет выпущен в основной версии и нарушит вашу бизнес-логику.
Тип ошибки - это тип интерфейса. Переменная error представляет любое значение, которое может быть описано как строка. Вот объявление интерфейса:
type error interface {
Error() string
}
Наиболее часто используемая реализация ошибок - это пакет ошибок, не экспортируемый тип errorString:
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
Посмотрите этот вывод рабочего кода (The Go Playground):
package main
import (
"errors"
"fmt"
"io"
)
func main() {
err1 := fmt.Errorf("Error")
err2 := errors.New("Error")
err3 := io.EOF
fmt.Println(err1) //Error
fmt.Printf("%#v\n", err1) // &errors.errorString{s:"Error"}
fmt.Printf("%#v\n", err2) // &errors.errorString{s:"Error"}
fmt.Printf("%#v\n", err3) // &errors.errorString{s:"EOF"}
}
выход:
Error
&errors.errorString{s:"Error"}
&errors.errorString{s:"Error"}
&errors.errorString{s:"EOF"}
Также см.: Операторы сравнения
Операторы сравнения сравнивают два операнда и выдают нетипизированное логическое значение. В любом сравнении первый операнд должен быть назначен типу второго операнда или наоборот.
Операторы равенства
==
и!=
Применяются к операндам, которые сравнимы.Значения указателя сопоставимы. Два значения указателя равны, если они указывают на одну и ту же переменную или если оба имеют значение nil. Указатели на различные переменные нулевого размера могут совпадать или не совпадать.
Значения интерфейса сопоставимы. Два значения интерфейса равны, если они имеют идентичные динамические типы и одинаковые динамические значения или оба имеют значение nil.
Значение x неинтерфейсного типа X и значение t интерфейсного типа T сравнимы, когда значения типа X сравнимы и X реализует T. Они равны, если динамический тип t идентичен X, а динамическое значение t равно x,
Значения структур сравнимы, если все их поля сопоставимы. Два значения структуры равны, если их соответствующие непустые поля равны.
Так:
1- Вы можете использовать Error()
, как этот рабочий код (The Go Playground):
package main
import (
"errors"
"fmt"
)
func main() {
err1 := errors.New("Token is expired")
err2 := errors.New("Token is expired")
if err1.Error() == err2.Error() {
fmt.Println(err1.Error() == err2.Error()) // true
}
}
выход:
true
2- Также вы можете сравнить его с nil
, как этот рабочий код (The Go Playground):
package main
import (
"errors"
"fmt"
)
func main() {
err1 := errors.New("Token is expired")
err2 := errors.New("Token is expired")
if err1 != nil {
fmt.Println(err1 == err2) // false
}
}
выход:
false
3- Также вы можете сравнить его с точно такой же ошибкой, как этот рабочий код
(The Go Playground):
package main
import (
"fmt"
"io"
)
func main() {
err1 := io.EOF
if err1 == io.EOF {
fmt.Println("err1 is : ", err1)
}
}
выход:
err1 is : EOF
Объявление ошибки и сравнение ее с "==
" (как в err == myPkg.ErrTokenExpired
) больше не является лучшей практикой для Go 1.13 (Q3 2019)
Примечания к выпуску упоминают:
Go 1.13 contains support for error wrapping, as first proposed in the Error Values proposal и discussed on the associated issue.
Ошибка
e
может обернуть другую ошибкуw
, предоставив методUnwrap
, который возвращаетw
.
Обаe
иw
доступны для программ, что позволяетe
предоставлять дополнительный контекст дляw
или интерпретировать его, в то же время позволяя программам принимать решения на основеw
.To support wrapping,
fmt.Errorf
now has a%w
verb for creating wrapped errors, и three new functions in theerrors
package (errors.Unwrap
,errors.Is
иerrors.As
) simplify unwrapping и inspecting wrapped errors.
Итак, FAQ по значению ошибки объясняет:
Вы должны быть готовы к тому, что ошибки, которые вы получаете, могут быть перенесены.
Если вы в настоящее время сравниваете ошибки, используя
==
, используйте вместо этогоerrors.Is
.
Пример:if err == io.ErrUnexpectedEOF
становится
if errors.Is(err, io.ErrUnexpectedEOF)
- Проверяет форму, если
err != nil
не нужно менять.- Сравнения с
io.EOF
не нужно менять, потому чтоio.EOF
никогда не следует переносить.Если вы проверяете тип ошибки, используя утверждение типа или переключатель типа, используйте вместо этого
errors.As
. Пример:if e, ok := err.(*os.PathError); ok
становится
var e *os.PathError if errors.As(err, &e)
Также используйте этот шаблон, чтобы проверить, реализует ли ошибка интерфейс. (Это один из тех редких случаев, когда указатель на интерфейс уместен.)
Перепишите переключатель типа как последовательность
if-elses
.