Guess the output
Let’s take this method which is simple nil check
func IsErrNil(err error) {
println(err == nil)
}
Let’s start directly with snippets and guess their output
func main() {
var err error
fmt.Println(err)
fmt.Println(err == nil)
IsErrNil(err)
}
What do you think the output is?
If you think that it’s
<nil>
true
true
Then right! Easy, cause in Go default value of error is nil
Let’s go to the next snippet, here I am defining my own custom error type that
satisfies the error interface in Go
type CustomErr struct{}
func (c *CustomErr) Error() string {
if c == nil {
return "<nil>"
}
return "custom error"
}
func main() {
var myCustomErr *CustomErr
fmt.Println(myCustomErr)
fmt.Println(myCustomErr == nil)
IsErrNil(myCustomErr)
}
If you think that output is
<nil>
true
true
Then it’s wrong! The correct output is
<nil>
true
false
Why?
Let’s add this function that will print the type of the error
func printType(err error) {
t := reflect.TypeOf(err)
v := reflect.ValueOf(err)
if t == nil {
fmt.Println("type = <nil>, no value")
return
}
if v.Kind() == reflect.Ptr && v.IsNil() {
fmt.Printf("type = %v, value = <nil>\n", t)
} else {
fmt.Printf("type = %v, value = %v\n", t, v)
}
}
If we call printType(myCustomErr), it will output the following
type = *main.CustomErr, value = <nil>
Calling printType(err), it will output
type = <nil>, no value
Here is the catch! In Go, an interface is nil only if it’s type and value
are nil
The function IsErrNil takes an interface error so the err == nil will
evaluate to false in case of myCustomErr cause it’s type is not nil
Conclusion
Bugs like these sometimes can be unintuitive, so keep your tests around :)
Here is final source code code