drq61040 2019-09-20 10:39
浏览 28
已采纳

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

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?
  • 写回答

1条回答 默认 最新

  • douqian1975 2019-09-20 12:27
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题