Golang 错误 wrapunwrap && 用 errors.Is() 检查类型。

问题描述 投票:0回答:1

我正在检查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.orgp-hSukZ-gii2。

编辑:看来,任何参数的差异,包括在包装错误参数。Err,将导致无法找到该类型与 errors.Is().

go error-handling wrapper trace
1个回答
1
投票

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

e := &somePointerWrapperError{"Hi!", nil}
ew := fmt.Errorf("whoa!: %w", e)

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

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

那么如何检测这种 "类型 "的错误呢? 得其值 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.orgpCttKThLasXD。

© www.soinside.com 2019 - 2024. All rights reserved.