Even experienced go developers can get tripped up by this one edge case in golang.
In golang nil is not always equal to nil.
A variable that holds an interface can have a nil value but still pass a nil check.
An interface value is internally stored as two words:
Type word – the dynamic type of the value stored in the interface.
Value word – the actual value itself (or a pointer to it).
An interface is only nil if both the Type and the Value are nil.
This means that you could have a pointer with the type *int but a value equal to nil, then assign it to an interface and the interface would not be nil! This can easily translate into a panic in your go applications.
Code
package main
import (
"fmt"
)
type MyErr struct{ msg string }
func (e *MyErr) Error() string { return e.msg }
func main() {
var i interface{} // type=nil, value=nil
fmt.Println("i == nil?", i == nil)
var p *int = nil // typed nil pointer
i = p // type=*int, value=nil
fmt.Println("i == nil?", i == nil)
fmt.Printf("dynamic: %T, value: %v\n", i, i)
// error example
var me *MyErr = nil // typed nil *MyErr
var err error = me // type=*MyErr, value=nil -> non-nil interface
fmt.Println("err == nil?", err == nil)
// Correct: when you mean no error, assign untyped nil
err = nil
fmt.Println("err == nil after explicit nil?", err == nil)
}
Output
i == nil? true
i == nil? false
dynamic: *int, value: <nil>
err == nil? false
err == nil after explicit nil? true