带有错误的Golang错误包装/解包&&类型检查。is()

时间:2020-06-18 03:40:42

标签: go error-handling wrapper trace

我正在检查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()找到类型。

2 个答案:

答案 0 :(得分: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.org/p/CttKThLasXD

答案 1 :(得分:1)

远程相关,但可能对某人有所帮助:我花了一些时间才意识到 <CollectionView x:Name="CollectionEditIcon" Margin="10,5,10,5" HorizontalOptions="Center" SelectionMode="None"> <CollectionView.ItemsLayout> <GridItemsLayout Orientation="Vertical" Span="1" VerticalItemSpacing="5" HorizontalItemSpacing="5"/> </CollectionView.ItemsLayout> <CollectionView.ItemTemplate> <DataTemplate> <Grid> <Entry x:Name="EntryEdit" Text="{Binding id}" TextColor="Black" FontSize="16" MaxLength="25" TextChanged="Entry_TextChanged" IsReadOnly="{Binding Edit}" Unfocused="EntryEdit_Unfocused"/> 实际上期望指向目标的双指针,而 errors.As(...) 则没有:

errors.Is(...)
相关问题