当错误已返回时,从延迟函数返回错误

当错误已返回时,从延迟函数返回错误

问题描述:

Update: I think now that there is no universal answer to this question. We can return both errors using the technique explained in the answer. I think that the most important thing here is not to forget the case when we have two errors and somehow handle it.

Notes: There are many questions on SO about how to return an error from deferred function. This is not a question here.

(In Go) What is the proper way to return an error from a deferred function when the function is already returning an error. For example

func errorMaker() (err error) {
    defer func() {
        err = errors.New("Deferred error")
    }()

    err = errors.New("Some error")
    return
}
func main() {
    err := errorMaker()
    fmt.Printf("Error: %v
", err)
}

In the code above the error returned by the deferred function overwrites the error returned by the function. What is the canonical way to return both errors? If another programmer uses my function what result might she expect from the function when the function returns 'two errors'?

Should I use Error wrapping for this?

Additional notes:

  1. As @Volker says in his comment I write some application specific handling for this error. Because I know what should be done based on nature of the errors.
  2. I think my question is - if I want to return all errors from the function what is the best way to combine them in my scenario?

更新:我认为现在对此问题没有统一的答案。 我们可以使用答案中说明的技术返回两个错误。 我认为,最重要的是,当我们遇到两个错误并以某种方式处理时,不要忘记这种情况。 p>

注意:SO上有很多有关如何从延迟函数返回错误的问题。 这不是这里的问题。 p>

(在执行中)什么是从延迟函数返回错误的正确 em>方法? 该函数已经返回错误。 对于示例 p>

  func errorMaker()  (错误错误){
延迟func(){
错误=错误。New(“延迟错误”)
}()
 
错误=错误.New(“某些错误”)
返回
  } 
func main(){
 err:= errorMaker()
 fmt.Printf(“错误:%v 
”,err)
} 
  code>  pre> 
 
 在上面的代码中,延迟函数返回的错误将覆盖该函数返回的错误。 返回两个错误的规范方法是什么? 如果另一个程序员使用我的函数,当函数返回“两个错误”时,她会从函数中得到什么结果? p> 
 
 

我应该使用为此错误包装? p>

其他说明: p>

    \ n
  1. 正如@Volker在他的评论中所说,我为此错误编写了一些特定于应用程序的处理。 因为我知道根据错误的性质应该采取的措施。 li>
  2. 我认为我的问题是-如果我想从函数中返回所有错误,在我的情况下将其组合的最佳方法是什么 ? li> ol> div>

Disclaimer: I don't know if the following advice can be seen as "standard" or "widely-accepted".

Should I use Error wrapping for this?

Short answer: yes (I would do so).


Go 1.12 and earlier

What I do when I need my errors to convey some specific meaning, without foregoing the error interface, I create a wrapper that implements the error interface - Error() string -. This wrapper contains all extra information I need.

If the caller is aware of the existence of those extra info, it can unwrap the error with a cast and find those info. With the added benefit that unaware callers can just handle the error as a generic error.

type MyError struct {
    DeferredError error
}

// Implements 'error' interface
func (e MyError) Error() string {
    // format to string
}

func someFunc() error {
    // might return an instance of MyError
}

...

// Caller code
err := someFunc()
if err != nil {
    if myErr, ok := err.(*MyError); ok {
        // here you can access the wrapped info
        fmt.Println(myErr.DeferredError)

    } else {
        // otherwise handle the error generically
    }
}


Go 1.13 onwards

With Go.13 you can use errors.As to unwrap an error. From the official docs:

[The method] As finds the first error in err's chain that matches target, and if so, sets target to that error value and returns true. The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.

var myErr *MyError
if errors.As(err, &myErr) {
    // here you can access the wrapped info
    fmt.Println(myErr.DeferredError)
} else {
    // otherwise handle the error generically 
}

As the docs say the myErr variable is populated as a side-effect of calling As.