处理go中的多个错误的最惯用的方法是什么?
我应该尝试包装错误并返回两个错误吗?
if err := foo(bar, obj); err != nil {
// how to do I avoid losing this error?
err := l.fixup(obj)
if err != nil {
// but this error is the not the one from foo?
}
return err
}
return l.fixup(obj)
答案 0 :(得分:1)
您可以使用UPDATE users
SET membership_expiry_date = membership_expiry_date + 3* INTERVAL '1 day'
函数从Dave Cheney的这一出色软件包中为原始错误添加上下文
https://github.com/pkg/errors
Wrap
函数返回一个新错误,该错误将上下文添加到原始错误中。
errors.Wrap
在您的情况下,这将是:
func Wrap(cause error, message string) error
答案 1 :(得分:0)
在问题的两个代码路径中都调用var test = new Nightmare()
.goto("https://www.google.com")
.evaluate(function() {
var element = document.getElementById(elementId);
element.parentNode.removeChild(element);
});
方法。通过在if语句之外调用fixup
来简化代码。
如果您希望fixup
中的错误优先于foo
中的错误,则可以这样做。
fixup
答案 2 :(得分:0)
如果必须链接错误并返回,则这完全取决于错误的含义以及要通知调用方的错误。通常,当发生错误不应停止路径并随后进行调用时(例如,foo
然后是fixup
),您可能会记录第一个错误并返回第二个错误,因为这很可能与您的功能最相关。
还有一些用于包装错误的软件包,因此您可以从多个错误中构建一个错误。
有fmt.Errorf
的标准软件包,您可以汇编多个错误。
还有https://github.com/hashicorp/go-multierror,可让您将多个错误保留在一个错误中。
在您的情况下,如果您想使两条错误消息都冒出来,我会做类似的事情:
err := foo(bar, obj)
if fixupErr := l.fixup(obj); fixupErr != nil {
if err != nil {
return fmt.Errorf("foo err: %s\nfixup err: %s\n", err, fixupErr)
}
return fixupErr
}
return err
答案 3 :(得分:0)
无论如何,您都编码呼叫l.fixup(obj)
。如果foo(bar, obj)
返回错误,则完成 处理并调用l.fixup(obj)
-否则仅调用l.fixup(obj)
。因此,您的代码可以像这样重新排列:
// err will only be valid within the if-then-else-construct
if err := foo(bar, obj); err != nil {
// handle error from foo(bar,obj)
// you can even return it, if you wanted to
// For the sake of this example, we simply log it
log.Println("Executing foo: %s", err)
}
return l.fixup(obj)
此外,如果您想区分error
或foo
可能返回的错误,则可以使用l.fixup
是为您带来优势的接口。为此,您可以为其中一个(或两个)创建类型错误,然后使用所谓的类型开关来评估错误的类型。
package main
import (
"errors"
"fmt"
)
// FooError is the error to be returned by foo
type FooError struct {
Bar string
}
// Error implements the interface
func (f FooError) Error() string {
return fmt.Sprintf("%s: interface is nil", f.Bar)
}
// dummy foo func
func foo(bar string, in interface{}) error {
if in == nil {
return FooError{Bar: bar}
}
return nil
}
// dummy fixup func
func fixup(in interface{}) error {
if in == nil {
return errors.New("Interface is nil")
}
return nil
}
// a wrapper, containing a variation of above code
func wrap(bar string) error {
if err := foo(bar, nil); err != nil {
// handle error from foo(bar,obj)
// you can even return it, if you wanted to
return err
}
return fixup(nil)
}
func main() {
err := wrap("test")
// The type switch itself
switch err.(type) {
case FooError:
// We have a FooError, so we can deal with it accordingly
fmt.Println("Foo Error:",err)
default:
// Every other error is handled by the default block
fmt.Println("Std Error:",err)
}
}
但是,这并不完全正确。如果调用foo
并返回错误而阻止执行逻辑 not 中的其他操作,则恐慌可能是有效的。