我有一个错误对象,当在控制台上打印给我 Token is expired
如何将其与特定错误值进行比较.我尝试了这个,但没有奏效.
if err == errors.New("Token is expired") {
log.Printf("Unauthorised: %s\n", err)
}
Run Code Online (Sandbox Code Playgroud)
Von*_*onC 38
==
在err == myPkg.ErrTokenExpired
Go 1.13(2019 年第 3 季度)中声明错误并将其与 ' '(如)进行比较不再是最佳实践
该发行说明中提到:
Go 1.13 包含对错误包装的支持,正如错误值提案中首次提出的那样,并在相关问题上进行了讨论。
一个错误
e
可以w
通过提供一个Unwrap
返回的方法来包装另一个错误w
。
双方e
并w
可供程序,允许e
以提供额外的上下文w
或重新解释它同时还允许根据程序做出判断w
。为了支持包装,
fmt.Errorf
现在有一个%w
用于创建包装错误的动词,并且errors
包中的三个新函数(errors.Unwrap
,errors.Is
和errors.As
) 简化了展开和检查包装错误。
所以错误值常见问题解释了:
你需要准备好你得到的错误可能会被包装。
如果您当前使用 比较错误
==
,请errors.Is
改用。
例子:Run Code Online (Sandbox Code Playgroud)if err == io.ErrUnexpectedEOF
变成
Run Code Online (Sandbox Code Playgroud)if errors.Is(err, io.ErrUnexpectedEOF)
- 如果
err != nil
不需要更改,则检查表格。- 比较
io.EOF
不需要改变,因为io.EOF
不应该被包装。如果您使用类型断言或类型 switch检查错误类型,请
errors.As
改用。例子:Run Code Online (Sandbox Code Playgroud)if e, ok := err.(*os.PathError); ok
变成
Run Code Online (Sandbox Code Playgroud)var e *os.PathError if errors.As(err, &e)
还可以使用此模式检查错误是否实现了接口。(这是指向接口的指针合适的罕见情况之一。)
将类型开关重写为
if-elses
.
Grz*_*Żur 30
在库中定义错误值
package fruits
var NoMorePumpkins = errors.New("No more pumpkins")
Run Code Online (Sandbox Code Playgroud)
不要errors.New
在代码中的任何位置创建错误,而是在发生错误时返回预定义的值,然后您可以执行以下操作:
package shop
if err == fruits.NoMorePumpkins {
...
}
Run Code Online (Sandbox Code Playgroud)
请参阅io
包装错误以供参考.
Sri*_*har 28
尝试
err.Error() == "Token is expired"
Run Code Online (Sandbox Code Playgroud)
或者通过实现错误接口来创建自己的错误.
jus*_*ius 16
包导出它们使用的错误变量以便其他人可以与它们进行比较,这是惯用的.
例如,如果错误来自名为myPkg的包,并且定义为:
var ErrTokenExpired error = errors.New("Token is expired")
Run Code Online (Sandbox Code Playgroud)
您可以将错误直接比较为:
if err == myPkg.ErrTokenExpired {
log.Printf("Unauthorised: %s\n", err)
}
Run Code Online (Sandbox Code Playgroud)
如果错误来自第三方软件包并且不使用导出的错误变量,那么您可以做的只是与从err.Error()获得的字符串进行比较,但要小心这种方法,因为更改错误字符串可能不会在主要版本中发布,并会破坏您的业务逻辑.
小智 12
错误类型是接口类型.错误变量表示可以将自身描述为字符串的任何值.这是接口的声明:
type error interface {
Error() string
}
Run Code Online (Sandbox Code Playgroud)
最常用的错误实现是错误包的未导出错误字符串类型:
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
Run Code Online (Sandbox Code Playgroud)
看到这个工作代码输出(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"}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Error
&errors.errorString{s:"Error"}
&errors.errorString{s:"Error"}
&errors.errorString{s:"EOF"}
Run Code Online (Sandbox Code Playgroud)
另见:比较运算符
比较运算符比较两个操作数并产生无类型的布尔值.在任何比较中,第一个操作数必须可以分配给第二个操作数的类型,反之亦然.
等于运算符
==
并!=
适用于可比较的操作数.指针值具有可比性.如果两个指针值指向同一个变量或两者的值都为nil,则它们相等.指向不同零大小变量的指针可能相同也可能不相等.
接口值具有可比性.如果两个接口值具有相同的动态类型和相等的动态值,或者两者的值都为nil,则它们相等.
当类型X的值可比较且X实现T时,非接口类型X的值x和接口类型T的值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
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
true
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
false
Run Code Online (Sandbox Code Playgroud)
3-此外,您可以将其与完全相同的错误进行比较,例如此工作代码
(The Go Playground):
package main
import (
"fmt"
"io"
)
func main() {
err1 := io.EOF
if err1 == io.EOF {
fmt.Println("err1 is : ", err1)
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
err1 is : EOF
Run Code Online (Sandbox Code Playgroud)
参考:https://blog.golang.org/error-handling-and-go
不鼓励按字符串比较错误。相反,您应该按值比较错误。
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
}
Run Code Online (Sandbox Code Playgroud)
如果您是库作者并希望导出错误,则它特别有用,以便用户可以对不同类型的错误采取不同的行动。标准库也这样做。
这种方法的问题在于任何人都可以更改导出的值,因为 Go 不支持不可变值。但是,没有什么可以阻止您将字符串用作错误并将其设为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
}
Run Code Online (Sandbox Code Playgroud)
这是更冗长但更安全的方法。
您应该首先考虑按值比较错误,如其他解决方案中所述:
if errors.Is(err1, err2) {
// do sth
}
Run Code Online (Sandbox Code Playgroud)
然而,在某些情况下,从函数返回的错误有点复杂,例如,错误被多次包装,并且在每个函数调用中都添加了上下文,例如 ,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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您只是使用
if err1.Error() == err2.Error() {
// do sth
}
Run Code Online (Sandbox Code Playgroud)
如果是err1
或 ,您可能会面临 nil 指针取消引用运行时错误。err2
nil