如何将 golang 错误包装成不透明错误?

如何将错误包装成不透明的错误(如 Dave Cheney 在https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully中所述)?另外,我希望不透明错误有一个堆栈跟踪,并通过返回链保留它。


errors.Wrap()使用堆栈跟踪创建一个新错误,但不是我的不透明类型。我该怎么做(添加堆栈跟踪并使其成为MyErr临时 as true)?


package main


import (

    "fmt"

    "github.com/pkg/errors"

)


type temporary interface {

    Temporary() bool

}


func IsTemporary(err error) bool {

    te, ok := err.(temporary)

    return ok && te.Temporary()

}


type MyError struct {

    error

    isTemporary bool

}


func (e MyError) Temporary() bool {

    return e.isTemporary

}


func f1() error {   // imitate a function from another package, that produces an error

    return fmt.Errorf("f1 error")

}


func f2() error {

    err := f1()

    myErr := errors.Wrap(err, "f2 error")   // Wrap() adds the stacktrace

    // how to wrap it as a temporary MyErr?

    return myErr

}


func f3() error {

    err := f2()

    return fmt.Errorf("f3 error: %+v", err) // don't Wrap() here or we get another stacktrace

}


func f4() error {

    err := f3()

    return fmt.Errorf("f4 error: %+v", err) // the '+' isn't needed here but does no harm

}


func main() {

    err := f4()

    if err != nil {

        if IsTemporary(err) {

            fmt.Println("temporary error")

        }

        fmt.Printf("oops: %+v\n", err)

    }

}

这是正确的,只是我想先看到“临时错误”。

假设f1实际上在第 3 方或内置代码中,返回标准error类型。 f2是我的代码中收到该错误的第一个函数,需要在适当的时候将其设为临时函数。(如果最初是临时的,那将是一个后续问题,但我想我可以弄清楚。)

我希望处理从我们的代码返回的错误的模式在整个项目中保持一致,这将是相对较大的。


慕勒3428872
浏览 85回答 1
1回答

慕哥6287543

你不能用这个github.com/pkg/errors函数真正做到这一点。这是因为用于包装的错误类型未导出,因此您无法将其嵌入到您自己的自定义错误中。但是,鉴于您不反对使用 stdliberrors包以外的错误库,以下是使用juju 错误包的方法(因为它的 Err 类型已导出):package mainimport (    "fmt"    "github.com/juju/errors")type temporary interface {    Temporary() bool}func IsTemporary(err error) bool {    for {        te, ok := err.(temporary)        if ok {            return te.Temporary()        }        er, ok := err.(*errors.Err)        if ok {            err = er.Underlying()            continue        }        return false    }}type MyError struct {    errors.Err    isTemporary bool}func (e MyError) Temporary() bool {    return e.isTemporary}func f1() error { // imitate a function from another package, that produces an error    return errors.Errorf("f1 error")}func f2() error {    err := f1()    wrappedErr := errors.Annotate(err, "f2 error")    return &MyError{        Err:         *wrappedErr.(*errors.Err),        isTemporary: true,    }}func f3() error {    err := f2()    return errors.Annotate(err, "f3 error")}func f4() error {    err := f3()    return errors.Annotate(err, "f4 error")}func main() {    err := f4()    if err != nil {        if IsTemporary(err) {            fmt.Println("temporary error")        }        if e, ok := err.(*errors.Err); ok {            fmt.Printf("oops: %+v\n", e.StackTrace())        }    }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go