How to Check nil Interface in Golang?
--
It’s not a good idea to check an interface for nil
.
Try the following code:
type user interface{}
type staff struct{}func compareNil() {
var generic user
generic = nil // works as expected
fmt.Printf("value=%v type=%T (generic==nil)=%v\n", generic, generic, generic == nil) generic = (*staff)(nil) // fails my expectation
fmt.Printf("value=%v type=%T (generic==nil)=%v\n", generic, generic, generic == nil)
}
go playground: https://play.golang.org/p/7J9DeIjgNia
Output
value=<nil> type=*main.staff (generic==nil)=false
value=<nil> type=<nil> (generic==nil)=true
Why interface
check for nil
is special
An interface is a tuple of [Value, Type]. The nil
interface is a tuple [nil
, nil
]. However, the above code is an interface containing [nil
, *main.staff
] which is not nil
.
We can check for nil as follows:
func isNil(i interface{}) bool {
return i == nil || reflect.ValueOf(i).IsNil()
}
Here i==nil
means i
has [nil
, nil
] or has a nil
value in [nil
, *main.staff
].
But if the interface points to a type that has no Nil value:
s := "hello"
generic = s
fmt.Printf("value=%v type=%T type=%v\n", generic, generic, reflect.ValueOf(generic).IsNil())
The code panics:
panic: reflect: call of reflect.Value.IsNil on string Valuegoroutine 1 [running]:
reflect.Value.IsNil(...)
/Users/xxx/.goenv/versions/1.14.0/src/reflect/value.go:1063
main.compareNil()
/Users/xxx/go/1.14.0/src/mygo/interfaces/interfaces.go:48 +0x3b1
main.main()
/Users/xxx/go/1.14.0/src/mygo/interfaces/interfaces.go:29 +0x142
exit status 2
Conclusion
The safest way to compare nil interfaces is switch
on various types, the interface can assume. Never check as myinterface == nil
.