为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
呼如林 2022-06-13 10:56:00
我正在检查 Go v1.13 Go v1.14 中的错误跟踪。为什么似乎只能找到没有参数或带有值接收器的错误实现errors.Is()?这意味着能够包装的错误实现必须有一个值接收器才能被errors.Is().package mainimport (    "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:  falsehttps://play.golang.org/p/-hSukZ-gii2似乎参数的任何差异,包括包装的错误参数,Err都会导致无法找到类型errors.Is()。
查看完整描述

2 回答

?
qq_笑_17

TA贡献1818条经验 获得超7个赞

false您在尝试在另一个通过中查找一个错误时得到的原因errors.Is是因为 - 虽然这两个错误可能具有相同的字段值 - 它们是两个不同的内存指针:


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

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


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


errors.Is(ew, e)  // true

errors.Is(ew, e2) // false - because `ew` wraps `e` not `e2`

那么如何检测这种“类型”的错误并获取它的值:errors.As改用:


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

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


var ev *somePointerWrapperError


if errors.As(e2, &ev) {

    fmt.Printf("%#v\n", ev) // &somePointerWrapperError{Msg:"Hi!", Err:error(nil)}

}

https://play.golang.org/p/CttKThLasXD


查看完整回答
反对 回复 2022-06-13
?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

远程相关,但可能对某人有所帮助:我花了一些时间才意识到errors.As(...)实际上需要一个指向目标的双指针,而errors.Is(...)没有:


var _ error = (*CustomError)(nil) // ensure CustomError implements error


type CustomError struct {

    msg string

}


func (e CustomError) Error() string {

    return e.msg

}


func main() {

    err := &CustomError{"Hello, world!"} // Methods return pointers to errors, allowing them to be nil

    

    var eval *CustomError


    as := errors.As(err, &eval) // yes, that's **CustomError

    asFaulty := errors.As(err, eval) // no compile error, so it wrongly seems okay

    is := errors.Is(err, eval) // that's just *CustomError


    fmt.Printf("as: %t, asFaulty: %t, is: %t", as, asFaulty, is) // as: true, asFaulty: false, is: true

}


查看完整回答
反对 回复 2022-06-13
  • 2 回答
  • 0 关注
  • 325 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号