err*_*ynn 10 error-handling trace wrapper go
我正在检查 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
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/-hSukZ-gii2
似乎参数中的任何差异(包括包装的错误参数 )Err
都会导致无法使用 找到该类型errors.Is()
。
col*_*tor 14
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`
Run Code Online (Sandbox Code Playgroud)
那么如何检测这种“类型”的错误并获取其值: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)}
}
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/CttKThLasXD
远程相关,但也许它对某人有帮助:我花了一些时间才意识到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
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
17309 次 |
最近记录: |