如何将错误包装为不透明错误(如Dave在https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully中所描述的)?另外,我希望不透明的错误有一个堆栈跟踪,并通过返回链来保留它。
errors.Wrap()用堆栈跟踪创建一个新的错误,但不是我的不透明类型。如何做到这两种方式(添加堆栈跟踪并使其成为一个临时的MyErr,如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)
}
}这将打印以下内容:
oops: f4 error: f3 error: f1 error
f2 error
main.f2
/home/jlearman/projects/axon-internal/ibm/pocs/ibm-cloud/vmware-vms/err2.go:32
main.f3
/home/jlearman/projects/axon-internal/ibm/pocs/ibm-cloud/vmware-vms/err2.go:38
main.f4
/home/jlearman/projects/axon-internal/ibm/pocs/ibm-cloud/vmware-vms/err2.go:43
main.main
/home/jlearman/projects/axon-internal/ibm/pocs/ibm-cloud/vmware-vms/err2.go:48
runtime.main
/usr/local/go/src/runtime/proc.go:255
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1581这是正确的,但我想看到“临时错误”打印的第一。
假设f1实际上在第三方或内置代码中,返回一个标准的error类型。f2是我的代码中接收该错误的第一个函数,需要在适当的时候使它成为一个临时函数。(如果这是暂时的,那将是一个后续的问题,但我想我可以弄清楚。)
我希望处理代码返回的错误的模式在整个项目中保持一致,这将是相对较大的。
发布于 2021-12-20 17:47:45
使用github.com/pkg/errors函数并不能真正做到这一点。这是因为用于包装的错误类型未导出,因此不能将其嵌入到您自己的自定义错误中。
但是,由于您不反对使用stdlib errors包以外的错误库,下面是如何使用juju错误包(因为它的错误类型是导出的):
package main
import (
"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())
}
}
}https://stackoverflow.com/questions/70387666
复制相似问题