Go - 如何子类型包装的错误类?

我正在包装错误(添加上下文),然后区分两个错误。这是我目前用于测试的方案。(函数是否正确识别错误?我的问题是我如何减少冗长。


我有两个创建不同错误的函数:


func a() error {

    return errors.New("a")

}


func b() error {

    return errors.New("b")

}

它们都由传播erorr的第三个函数调用。


func doStuff() error {

    err := a()

    if err != nil {

        return WrapA{err}

    }

    err = b()

    if err != nil {

        return WrapB{err}

    }

    return nil

}

在我的主要功能中,我区分了这两个错误。


func main() {

    fmt.Println("Hello, playground")

    err := doStuff()

    

    switch err.(type) {

        case WrapA:

            fmt.Println("error from doing a")

        case WrapB: 

            fmt.Println("error from doing b")

        case nil:

            fmt.Println("nil")

        default:

            fmt.Println("unknown")

    }

}

目前为止,一切都好。不幸的是,要实现 和 ,我需要大量的代码:WrapAWrapB


type WrapA struct {

    wrappedError error

}


func (e WrapA) Error() string {

    return e.wrappedError.Error()

}


func (e WrapA) Unwrap() error {

    return e.wrappedError

}


type WrapB struct {

    wrappedError error

}


func (e WrapB) Error() string {

    return e.wrappedError.Error()

}


func (e WrapB) Unwrap() error {

    return e.wrappedError

}

在其他语言中,我会创建一个单一的结构,并让和继承自。但是我看不出有什么办法可以在Go中做到这一点。WrapWrapAWrapBWrap


关于如何减少混乱的任何想法?


围棋游乐场 https://play.golang.org/p/ApzHC_miNyV


编辑:在看到jub0bs的答案后,我想澄清:两者都是我无法控制的回调。它们可能会返回各种错误。这就是我包装它们的原因。a()b()


繁星点点滴滴
浏览 157回答 3
3回答

杨魅力

如果我正确地理解了这个问题,你确实可以简化事情:定义 和 作为包级变量,以便于使用和提高性能。aberror除非需要以编程方式访问只能在要包装的错误上下文中访问的值,否则很可能不需要声明这些自定义类型和错误类型。相反,您可以简单地将 %w 谓词与 fmt 结合使用。Errorf 以生成包装较低级别错误的新错误值。WrapAWrapB然后,您可以使用错误。在无标记内检查函数返回的更高级别错误的原因。switchdoStuff(操场)package mainimport (    "errors"    "fmt")var (    a = errors.New("a")    b = errors.New("b"))func doStuff() error {    err := a    if err != nil {        return fmt.Errorf("%w", err)    }    err = b    if err != nil {        return fmt.Errorf("%w", err)    }    return nil}func main() {    fmt.Println("Hello, playground")    switch err := doStuff(); {    case errors.Is(err, a):        fmt.Println("error from doing a")    case errors.Is(err, b):        fmt.Println("error from doing b")    case err == nil:        fmt.Println("nil")    default:        fmt.Println("unknown")    }}

jeck猫

添加一个结构化的错误版本,该版本沿着各种更具体的错误类型组成一个类型;Wrappackage mainimport (    "errors"    "fmt")func a() error {    return errors.New("something more specific broke in a")}func b() error {    return errors.New("something more specific broke in b")}func doStuff() error {    err := a()    if err != nil {        return ErrA{            Wrap:        Wrap{err: err},            SpecficProp: "whatever",        }    }    err = b()    if err != nil {        return ErrB{            Wrap:         Wrap{err: err},            SpecficProp2: "whatever else",        }    }    return nil}func main() {    fmt.Println("Hello, playground")    err := doStuff()    if target := (ErrA{}); errors.As(err, &target) {        fmt.Printf("%v\n", target)    } else if target := (ErrB{}); errors.As(err, &target) {        fmt.Printf("%v\n", target)    } else if err != nil {        fmt.Println("unknown")    } else {        fmt.Println("nil")    }}type Wrap struct {    err error}func (e Wrap) Error() string {    return e.err.Error()}func (e Wrap) Unwrap() error {    return e.err}type ErrA struct {    Wrap    SpecficProp interface{}}func (e ErrA) Error() string {    return fmt.Sprintf("got error of kind A with %#v, plus %T", e.SpecficProp, e.Unwrap())}type ErrB struct {    Wrap    SpecficProp2 interface{}}func (e ErrB) Error() string {    return fmt.Sprintf("got error of kind B with %#v, plus %T", e.SpecficProp2, e.Unwrap())}

忽然笑

如果可以的话,使用常量错误。然后,您可以打开错误本身。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go