使用errors.Is()进行错误换行/解包&&类型检查

我正在检查 Go v1.13 Go v1.14 中的错误跟踪。为什么似乎只能找到没有参数或带有值接收器的错误实现errors.Is()?这意味着能够包装的错误实现必须有一个值接收器才能被errors.Is().


package main


import (

    "fmt"

    "errors"

)


type someAtomicError struct {}

func (e *someAtomicError) Error() string { return "Hi!" }

func checkAtomicError() {

    e := &someAtomicError{}

    e2 := fmt.Errorf("whoa!: %w", e)

    e2IsE := errors.Is(e2, &someAtomicError{})

    fmt.Println("atomic error trace ---\t\t", e2, "\t\t--- is traceable: ", e2IsE)

}



type someWrapperError struct {

    Msg string

    Err error

}

func (e someWrapperError) Error() string { return fmt.Sprintf("%s: %v", e.Msg, e.Err) }

func (e someWrapperError) Unwrap() error { return e.Err }

func checkWrapperError() {

    e := someWrapperError{"Hi!", nil}

    e2 := fmt.Errorf("whoa!: %w", e)

    e2IsE := errors.Is(e2, someWrapperError{"Hi!", nil})

    fmt.Println("wrapper error trace ---\t\t", e2, "\t--- is traceable: ", e2IsE)

}



type somePointerWrapperError struct {

    Msg string

    Err error

}

func (e *somePointerWrapperError) Error() string { return fmt.Sprintf("%s: %v", e.Msg, e.Err) }

func (e *somePointerWrapperError) Unwrap() error { return e.Err }

func checkPointerWrapperError() {

    e := &somePointerWrapperError{"Hi!", nil}

    e2 := fmt.Errorf("whoa!: %w", e)

    e2IsE := errors.Is(e2, &somePointerWrapperError{"Hi!", nil})

    fmt.Println("pointer wrapper error trace ---\t", e2, "\t--- is traceable: ", e2IsE)

}



func main() {

    checkAtomicError()

    checkWrapperError() 

    checkPointerWrapperError()

}


//atomic error trace ---         whoa!: Hi!         --- is traceable:  true

//wrapper error trace ---        whoa!: Hi!: <nil>  --- is traceable:  true

//pointer wrapper error trace ---    whoa!: Hi!: <nil>  --- is traceable:  false

https://play.golang.org/p/-hSukZ-gii2


似乎参数的任何差异,包括包装的错误参数,Err都会导致无法找到类型errors.Is()。


呼如林
浏览 326回答 2
2回答

qq_笑_17

false您在尝试在另一个通过中查找一个错误时得到的原因errors.Is是因为 - 虽然这两个错误可能具有相同的字段值 - 它们是两个不同的内存指针:e&nbsp; := &somePointerWrapperError{"Hi!", nil}e2 := &somePointerWrapperError{"Hi!", nil} // e2 != eew := fmt.Errorf("whoa!: %w", e)errors.Is(ew, e)&nbsp; // trueerrors.Is(ew, e2) // false - because `ew` wraps `e` not `e2`那么如何检测这种“类型”的错误并获取它的值:errors.As改用:e := &somePointerWrapperError{"Hi!", nil}e2 := fmt.Errorf("whoa!: %w", e)var ev *somePointerWrapperErrorif errors.As(e2, &ev) {&nbsp; &nbsp; fmt.Printf("%#v\n", ev) // &somePointerWrapperError{Msg:"Hi!", Err:error(nil)}}https://play.golang.org/p/CttKThLasXD

泛舟湖上清波郎朗

远程相关,但可能对某人有所帮助:我花了一些时间才意识到errors.As(...)实际上需要一个指向目标的双指针,而errors.Is(...)没有:var _ error = (*CustomError)(nil) // ensure CustomError implements errortype CustomError struct {&nbsp; &nbsp; msg string}func (e CustomError) Error() string {&nbsp; &nbsp; return e.msg}func main() {&nbsp; &nbsp; err := &CustomError{"Hello, world!"} // Methods return pointers to errors, allowing them to be nil&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; var eval *CustomError&nbsp; &nbsp; as := errors.As(err, &eval) // yes, that's **CustomError&nbsp; &nbsp; asFaulty := errors.As(err, eval) // no compile error, so it wrongly seems okay&nbsp; &nbsp; is := errors.Is(err, eval) // that's just *CustomError&nbsp; &nbsp; fmt.Printf("as: %t, asFaulty: %t, is: %t", as, asFaulty, is) // as: true, asFaulty: false, is: true}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go