如何处理多个错误?

时间:2019-03-22 18:08:56

标签: go error-handling

处理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)

4 个答案:

答案 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)

此外,如果您想区分errorfoo可能返回的错误,则可以使用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 中的其他操作,则恐慌可能是有效的。