Preface
When writing functions in go language, nil is often returned, and then it is determined whether the return value is empty outside the function. There is a bug here, please record it
Question 1
(*Type)(nil) ≠ nil
func returnsError() error { var p *MyError = nil if bad() { p = ErrBad } return p // Will always return a non-nil error. }
The p returned by the function returnsError above will never be equal to nil.
Why is this? Because error is an interface. The comparison between interfaces requires ensuring that the Type and Value of the two are equal.
nil in the language can be understood as p returned in an interface code where both Type and Value are empty. Although Value is empty, Type is *MyError, so p!=nil.
Correct writing
func returnsError() error { if bad() { return ErrBad } return nil }
This problem is not only a problem that occurs when an error is thrown, but any scene that returns to the interface needs to be paid attention to.
Question 2
type CustomError struct { Metadata map[string]string Message string } func (c CustomError) Error() string { return } var ( ErrorA = CustomError{Message:"A", Matadata: map[string]string{"Reason":""}} ErrorB = CustomError{Message:"B"} ) func DoSomething() error { return ErrorA }
After receiving an error externally, we often use to determine the error type:
err:=DoSomething() if (err, ErrorA) { // handle err }
But you will find that the above judgment is false in any case. Research the source code:
func Is(err, target error) bool { if target == nil { return err == target } isComparable := (target).Comparable() for { if isComparable && err == target { return true } if x, ok := err.(interface{ Is(error) bool }); ok && (target) { return true } if err = (err); err == nil { return false } } }
You can see that this is a recursive process on an error tree. The end condition of the true value is err==target, but the premise is that the target itself must be comparable.
So if we put a map into an error struct, it will cause the error to become incomparable and we will never be able to successfully compare.
The solution is also very simple, which is to define the pointer type with Error:
var ( ErrorA = &CustomError{Message:"A", Matadata: map[string]string{"Reason":""}} ErrorB = &CustomError{Message:"B"} )
Comparing pointer types only requires checking whether to point to the same object, so that the comparison can be smooth.
refer to
[1]In-depth understanding of Go Comparable Type
The above is the detailed content of the analysis of avoiding pits when Go function returns nil when encountering problems. For more information about Go function returns nil when avoiding pits when Go function returns nil. Please pay attention to my other related articles!