当错误已返回时,从延迟函数返回错误
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:
- 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.
- 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>
我应该使用为此错误包装? p>
其他说明: p>
func errorMaker() (错误错误){
延迟func(){
错误=错误。New(“延迟错误”)
}()
错误=错误.New(“某些错误”)
返回
}
func main(){
err:= errorMaker()
fmt.Printf(“错误:%v
”,err)
}
code> pre>
在上面的代码中,延迟函数返回的错误将覆盖该函数返回的错误。 返回两个错误的规范方法是什么? 如果另一个程序员使用我的函数,当函数返回“两个错误”时,她会从函数中得到什么结果? p>
\ n
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
.