如何比较Golang错误对象

时间:2016-08-24 10:46:09

标签: go

我有一个错误对象,在控制台上打印时会给我Token is expired

如何将其与特定错误值进行比较。我尝试了这个但是没有用。

if(err == errors.New("Token is expired")){
      log.Printf("Unauthorised: %s\n", err)
}

7 个答案:

答案 0 :(得分:25)

尝试

double no=12.786;
DecimalFormat dec = new DecimalFormat("#0.00");
System.out.println(dec.format(no));

或者通过实现错误界面来创建自己的错误。

答案 1 :(得分:24)

在库中定义错误值

package fruits

var NoMorePumpkins = errors.New("No more pumpkins")

不要在代码中的任何位置创建errors.New错误,但每当发生错误时都会返回预定义值,然后您可以执行以下操作:

package shop

if err == fruits.NoMorePumpkins {
     ...
}

请参阅io包错误以供参考。

答案 2 :(得分:12)

导出错误变量的包是惯用的,因此其他人可以与它们进行比较。

E.g。如果错误来自名为 myPkg 的包,并且定义为:

var ErrTokenExpired error = errors.New("Token is expired")

您可以将错误直接比较为:

if err == myPkg.ErrTokenExpired {
    log.Printf("Unauthorised: %s\n", err)
}

如果错误来自第三方软件包并且不使用导出的错误变量,那么您可以做的只是与从err.Error()获得的字符串进行比较,但要小心这种方法错误字符串可能不会在主要版本中发布,并且会破坏您的业务逻辑。

答案 3 :(得分:7)

错误类型是接口类型。错误变量表示可以将自身描述为字符串的任何值。这是界面的声明:

type error interface {
    Error() string
}

最常用的错误实现是错误包的未导出错误字符串类型:

// 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"}

另见:Comparison operators

  

比较运算符比较两个操作数并产生一个无类型的布尔值   值。在任何比较中,第一个操作数必须可分配给   第二个操作数的类型,反之亦然。

     

等于运算符==!=适用于操作数   可比性。

     

指针值具有可比性。如果它们两个指针值相等   指向相同的变量或者两者的值都为零。指针   不同的零大小变量可能相等也可能不相等。

     

界面值具有可比性。如果两个接口值相等   它们具有相同的动态类型和相同的动态值,或者两者都有   没有价值。

     

非接口类型X的值x和接口类型T的值t   当X类型的值具有可比性且X实现时,可比较   如果t的动态类型与X和t相同,它们是相等的   动态值等于x。

     

如果所有字段都具有可比性,则结构值具有可比性。二   如果相应的非空白字段是,则struct值相等   相等。

所以:

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

参考:https://blog.golang.org/error-handling-and-go

答案 4 :(得分:6)

声明错误并将其与'=='(如err == myPkg.ErrTokenExpired比较)已不再是Go 1.13(2019年第三季度)的最佳做法

release notes提到:

  

Go 1.13包含对错误包装的支持,该支持首先在Error Values proposal中提出,并在associated issue上进行了讨论。

     

错误e可以通过提供返回w的{​​{1}}方法来包装另一个错误Unwrap
  we都可供程序使用,从而允许we提供附加上下文或重新解释它,同时仍允许程序根据{{1}做出决定}。

     

为了支持包装,fmt.Errorf现在有一个w动词来创建包装错误,并在errors包中提供了三个新功能(errors.Unwraperrors.Iserrors.As)简化了包装和检查包装的错误。

因此Error Value FAQ解释:

  

您需要做好准备,以防您收到的错误得到解决。

     

如果您当前使用w比较错误,请改用%w
  示例:

==
     

成为

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 的序列。

答案 5 :(得分:6)

不鼓励按字符串比较错误。相反,您应该按值比较错误。

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

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
}

这是更冗长但更安全的方法。

答案 6 :(得分:0)

您应该首先考虑按值比较错误,如其他解决方案中所述:

if errors.Is(err1, err2) {
  // do sth
}

但是在某些情况下,函数返回的错误有点复杂,例如一个错误被多次包装,在每个函数调用中添加一个上下文,如 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
}

如果 err1err2nil,您可能会面临 nil 指针取消引用运行时错误。