我有一个错误值,当打印在控制台上时,该值为Token is expired如何将其与特定的错误值进行比较?我尝试了以下方法,但没有效果:
Token is expired
if err == errors.New("Token is expired") { log.Printf("Unauthorised: %s\n", err) }
qc6wkl3g1#
声明错误并将其与' == '(如err == myPkg.ErrTokenExpired)进行比较不再是Go 1.13(Q3 2019)的最佳实践发行说明提到:Go语言1.13包含了对**错误 Package **的支持,这是在Error Values proposal中首次提出并在associated issue中讨论过的。通过提供返回w的Unwrap方法,错误e可以 Package 另一个错误w。e和w都可用于程序,允许e向w提供额外的上下文或重新解释它,同时仍然允许程序基于w做出决策。为了支持 Package ,fmt.Errorf现在有一个用于创建 Package 错误的%w动词,并且errors包中的三个新函数(errors.Unwrap、errors.Is和errors.As)简化了展开和检查 Package 错误的过程。因此Error Value FAQ解释道:
==
err == myPkg.ErrTokenExpired
w
Unwrap
e
fmt.Errorf
%w
errors
errors.Unwrap
errors.Is
errors.As
您需要做好准备,以防收到的错误被 Package 。
如果您目前使用==比较错误,请改用errors.Is。示例:
if err == io.ErrUnexpectedEOF
变成
if errors.Is(err, io.ErrUnexpectedEOF)
err != nil
io.EOF
如果使用类型Assert或类型开关检查错误类型,请改用errors.As。示例:
if e, ok := err.(*os.PathError); ok
var e *os.PathError if errors.As(err, &e)
还可以使用此模式检查错误是否实现了接口。(这是一种非常罕见的情况,此时指向接口的指针是合适的。)将类型开关重写为序列if-elses。
if-elses
vjhs03f72#
此答案适用于Go 1.12及更早版本。
在库中定义错误值
package fruits var NoMorePumpkins = errors.New("No more pumpkins")
不要在代码中的任何位置使用errors.New创建错误,而是在发生错误时返回预定义的值,然后可以执行以下操作:
errors.New
package shop if err == fruits.NoMorePumpkins { ... }
请参阅io套件错误以取得指涉。这可以通过添加隐藏检查实现的方法来改进,并使客户端代码对fruits包中的更改具有更强的免疫力。
io
fruits
package fruits func IsNoMorePumpkins(err error) bool { return err == NoMorePumpkins }
请参阅os套件错误以取得指涉。
os
ctzwtxfj3#
尝试
err.Error() == "Token is expired"
或者通过实现错误接口来创建您自己的错误。
7gyucuyw4#
对于包来说,导出它们使用的错误变量是惯用的,这样其他人就可以与它们进行比较。例如,如果错误来自名为myPkg的软件包,并且定义为:
var ErrTokenExpired error = errors.New("Token is expired")
您可以直接比较以下错误:
if err == myPkg.ErrTokenExpired { log.Printf("Unauthorised: %s\n", err) }
如果错误来自第三方软件包,并且该软件包没有使用导出的错误变量,那么您可以做的就是简单地与从err.Error()中获得的字符串进行比较,但是要小心这种方法,因为更改错误字符串可能不会在主要版本中发布,并且会破坏您的业务逻辑。
t3psigkw5#
错误类型是一个接口类型。一个错误变量代表任何可以将自身描述为字符串的值。下面是接口的声明:
type error interface { Error() string }
最常用的错误实现是errors包的未导出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时,非接口类型X的值x和接口类型T的值t是可比较的。如果t的动态类型与X相同并且t的动态值等于x,则它们相等。如果结构值的所有字段都是可比较的,则结构值是可比较的。如果两个结构值对应的非空字段相等,则两个结构值相等。因此:1-您可以使用Error(),就像下面的工作代码(The Go Playground):
!=
Error()
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):
nil
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
参考:https://blog.golang.org/error-handling-and-go
xtupzzrd6#
不鼓励按字符串比较错误,而应该按值比较错误。
package main import "errors" var NotFound = errors.New("not found") func main() { if err := doSomething(); errors.Is(err, NotFound) { println(err) } } func doSomething() error { return NotFound }
如果你是库的作者,并且想导出错误,这样用户就可以对不同类型的错误采取不同的操作,这一点特别有用。标准库也可以做到这一点。这种方法的问题在于,输出的值可以被任何人修改,因为Go语言不支持不可变值,但是你可以把字符串作为一个错误,并把它设置为const。
const
package main type CustomError string func (ce CustomError) Error() string { return string(ce) } const NotFound CustomError = "not found" func main() { if err := doSomething(); errors.Is(err, NotFound) { println(err) } } func doSomething() error { return NotFound }
这是一种更详细但更安全的方法。
4xrmg8kj7#
您应该首先考虑按值比较错误,如其他解决方案中所述:
if errors.Is(err1, err2) { // do sth }
但是在某些情况下,函数返回的错误信息会比较复杂,例如,一个错误会被多次 Package ,在每次函数调用时都会添加一个上下文,比如fmt.Errorf("some context: %w", err),而您可能只想比较两个错误的错误信息。在这种情况下,您可以这样做:
fmt.Errorf("some context: %w", err)
// SameErrorMessage checks whether two errors have the same messages. func SameErrorMessage(err, target error) bool { if target == nil || err == nil { return err == target } return err.Error() == target.Error() } func main() { ... if SameErrorMessage(err1, err2) { // do sth } }
请注意,如果只使用
if err1.Error() == err2.Error() { // do sth }
如果err1或err2中有一个是nil,则可能会遇到nil指针取消引用运行时错误。
err1
err2
kdfy810k8#
为了补充@wst的回答,在某些情况下,errors.Is(err, NotFound)方法可能不起作用,原因我也在努力弄清楚。如果有人知道,请在评论中告诉我。
errors.Is(err, NotFound)
但我发现了一个更好的方法来使用它在以下方式是为我工作:
if NotFound.Is(err) { // do something }
其中var NotFound = errors.New("not found")是已声明的导出常见错误。在我的情况下,解决方案是
var NotFound = errors.New("not found")
if models.GetUnAuthenticatedError().Is(err) { // Do something }
sczxawaw9#
我想发布一个案例,其中errors.Is可以很好地处理non-comparable values的自定义错误。
non-comparable values
type CustomError struct { Meta map[string]interface{} Message string } func (c CustomError) Error() string { return c.Message } var ( ErrorA = CustomError{Message: "msg", Meta: map[string]interface{}{"key": "value"}} ) func DoSomething() error { return ErrorA } func main() { err := DoSomething() if errors.Is(err, ErrorA) { fmt.Println("error is errorA") } else { fmt.Println("error is NOT errorA") } }
输出量
error is NOT errorA
Playground原因是errors.Is检查target是否可比较
target
func Is(err, target error) bool { if target == nil { return err == target } isComparable := reflectlite.TypeOf(target).Comparable()
Go语言中的comparable类型有布尔值、数字、字符串、指针、通道、可比较类型的数组、字段都是可比较类型的结构由于CustomError的Meta map[string]interface{}不具有可比性,因此errors.Is检查失败。一种解决方法是将ErrorA = &CustomError{Message: "msg", Meta: map[string]interface{}{"key": "value"}}声明为指针。
comparable
CustomError
Meta map[string]interface{}
ErrorA = &CustomError{Message: "msg", Meta: map[string]interface{}{"key": "value"}}
9条答案
按热度按时间qc6wkl3g1#
声明错误并将其与'
==
'(如err == myPkg.ErrTokenExpired
)进行比较不再是Go 1.13(Q3 2019)的最佳实践发行说明提到:
Go语言1.13包含了对**错误 Package **的支持,这是在Error Values proposal中首次提出并在associated issue中讨论过的。
通过提供返回
w
的Unwrap
方法,错误e
可以 Package 另一个错误w
。e
和w
都可用于程序,允许e
向w
提供额外的上下文或重新解释它,同时仍然允许程序基于w
做出决策。为了支持 Package ,
fmt.Errorf
现在有一个用于创建 Package 错误的%w
动词,并且errors
包中的三个新函数(errors.Unwrap
、errors.Is
和errors.As
)简化了展开和检查 Package 错误的过程。因此Error Value FAQ解释道:
您需要做好准备,以防收到的错误被 Package 。
如果您目前使用
==
比较错误,请改用errors.Is
。示例:
变成
err != nil
是否需要更改。io.EOF
的比较不需要更改,因为io.EOF
不应被 Package 。如果使用类型Assert或类型开关检查错误类型,请改用
errors.As
。示例:变成
还可以使用此模式检查错误是否实现了接口。(这是一种非常罕见的情况,此时指向接口的指针是合适的。)
将类型开关重写为序列
if-elses
。vjhs03f72#
此答案适用于Go 1.12及更早版本。
在库中定义错误值
不要在代码中的任何位置使用
errors.New
创建错误,而是在发生错误时返回预定义的值,然后可以执行以下操作:请参阅
io
套件错误以取得指涉。这可以通过添加隐藏检查实现的方法来改进,并使客户端代码对
fruits
包中的更改具有更强的免疫力。请参阅
os
套件错误以取得指涉。ctzwtxfj3#
尝试
或者通过实现错误接口来创建您自己的错误。
7gyucuyw4#
对于包来说,导出它们使用的错误变量是惯用的,这样其他人就可以与它们进行比较。
例如,如果错误来自名为myPkg的软件包,并且定义为:
您可以直接比较以下错误:
如果错误来自第三方软件包,并且该软件包没有使用导出的错误变量,那么您可以做的就是简单地与从err.Error()中获得的字符串进行比较,但是要小心这种方法,因为更改错误字符串可能不会在主要版本中发布,并且会破坏您的业务逻辑。
t3psigkw5#
错误类型是一个接口类型。一个错误变量代表任何可以将自身描述为字符串的值。下面是接口的声明:
最常用的错误实现是errors包的未导出errorString类型:
请参见以下工作代码输出(The Go Playground):
输出:
另请参阅:比较运算子
比较运算符比较两个操作数并生成一个无类型的布尔值。在任何比较中,第一个操作数必须可赋值给第二个操作数的类型,反之亦然。
相等运算子
==
和!=
适用于可比较的算子。指针值是可比较的。如果两个指针指向同一个变量或都具有值nil,则它们的值相等。指向不同的零大小变量的指针可能相等,也可能不相等。
接口值是可比较的。如果两个接口值具有相同的动态类型和相等的动态值,或者都具有值nil,则这两个接口值相等。
当类型X的值是可比较的并且X实现T时,非接口类型X的值x和接口类型T的值t是可比较的。如果t的动态类型与X相同并且t的动态值等于x,则它们相等。
如果结构值的所有字段都是可比较的,则结构值是可比较的。如果两个结构值对应的非空字段相等,则两个结构值相等。
因此:
1-您可以使用
Error()
,就像下面的工作代码(The Go Playground):输出:
2-你也可以将它与
nil
进行比较,比如下面的工作代码(The Go Playground):输出:
3-您也可以将其与完全相同错误进行比较,如以下工作代码
(The Go Playground):
输出:
参考:https://blog.golang.org/error-handling-and-go
xtupzzrd6#
不鼓励按字符串比较错误,而应该按值比较错误。
如果你是库的作者,并且想导出错误,这样用户就可以对不同类型的错误采取不同的操作,这一点特别有用。标准库也可以做到这一点。
这种方法的问题在于,输出的值可以被任何人修改,因为Go语言不支持不可变值,但是你可以把字符串作为一个错误,并把它设置为
const
。这是一种更详细但更安全的方法。
4xrmg8kj7#
您应该首先考虑按值比较错误,如其他解决方案中所述:
但是在某些情况下,函数返回的错误信息会比较复杂,例如,一个错误会被多次 Package ,在每次函数调用时都会添加一个上下文,比如
fmt.Errorf("some context: %w", err)
,而您可能只想比较两个错误的错误信息。在这种情况下,您可以这样做:请注意,如果只使用
如果
err1
或err2
中有一个是nil
,则可能会遇到nil指针取消引用运行时错误。kdfy810k8#
为了补充@wst的回答,在某些情况下,
errors.Is(err, NotFound)
方法可能不起作用,原因我也在努力弄清楚。如果有人知道,请在评论中告诉我。但我发现了一个更好的方法来使用它在以下方式是为我工作:
其中
var NotFound = errors.New("not found")
是已声明的导出常见错误。在我的情况下,解决方案是
sczxawaw9#
我想发布一个案例,其中
errors.Is
可以很好地处理non-comparable values
的自定义错误。输出量
Playground
原因是
errors.Is
检查target
是否可比较Go语言中的
comparable
类型有布尔值、数字、字符串、指针、通道、可比较类型的数组、字段都是可比较类型的结构
由于
CustomError
的Meta map[string]interface{}
不具有可比性,因此errors.Is
检查失败。一种解决方法是将
ErrorA = &CustomError{Message: "msg", Meta: map[string]interface{}{"key": "value"}}
声明为指针。