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

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

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

Go
繁星点点滴滴 2022-09-26 20:28:54
我正在包装错误(添加上下文),然后区分两个错误。这是我目前用于测试的方案。(函数是否正确识别错误?我的问题是我如何减少冗长。我有两个创建不同错误的函数: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")    }}目前为止,一切都好。不幸的是,要实现 和 ,我需要大量的代码:WrapAWrapBtype 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()
查看完整描述

3 回答

?
杨魅力

TA贡献1811条经验 获得超5个赞

如果我正确地理解了这个问题,你确实可以简化事情:

  • 定义 和 作为包级变量,以便于使用和提高性能。aberror

  • 除非需要以编程方式访问只能在要包装的错误上下文中访问的值,否则很可能不需要声明这些自定义类型和错误类型。相反,您可以简单地将 %w 谓词与 fmt 结合使用。Errorf 以生成包装较低级别错误的新错误值。WrapAWrapB

  • 然后,您可以使用错误。在无标记内检查函数返回的更高级别错误的原因。switchdoStuff

(操场)

package main


import (

    "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")

    }

}


查看完整回答
反对 回复 2022-09-26
?
jeck猫

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

添加一个结构化的错误版本,该版本沿着各种更具体的错误类型组成一个类型;Wrap


package main


import (

    "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())

}


查看完整回答
反对 回复 2022-09-26
?
忽然笑

TA贡献1806条经验 获得超5个赞

如果可以的话,使用常量错误。然后,您可以打开错误本身。


查看完整回答
反对 回复 2022-09-26
  • 3 回答
  • 0 关注
  • 130 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信