golang中nil的判断
v == nil
Chan, Func, Map, Ptr, UnsafePointer, Slice
类型可直接判断是否为nil
。
type MyType struct {
}
func (*MyType) Do() {
}
func main() {
var v *MyType
fmt.Println(v == nil) // true
}
interface
判断一个interface
是否为nil
,要考虑多种情况,猜猜下面这个代码输出的是什么?
type MyType struct {
}
func main() {
var v interface{}
v = (*MyType)(nil)
fmt.Println(v == nil) // false
}
golang中判断一个interface
是否为nil
,会先判断类型,如果类型不一致,则返回false
。
在上面这个代码中的v == nil
,先判断了v的类型为(*MyType)
,判断nil的类型为interface{}
,则返回false
。
reflect
那么如何判断v是否为nil
呢?答:配合reflect
判断
type MyType struct {
}
func main() {
var v interface{}
v = (*MyType)(nil)
fmt.Println(reflect.ValueOf(v).IsNil()) // true
}
上面这个代码正确判断了v是否为nil
。
那reflect.Valueof(v).IsNil
是万能的判nil
方法吗?
看一下IsNil
的源码:
func (v Value) IsNil() bool {
k := v.kind()
switch k {
case Chan, Func, Map, Ptr, UnsafePointer:
if v.flag&flagMethod != 0 {
return false
}
ptr := v.ptr
if v.flag&flagIndir != 0 {
ptr = *(*unsafe.Pointer)(ptr)
}
return ptr == nil
case Interface, Slice:
// Both interface and slice are nil if first word is 0.
// Both are always bigger than a word; assume flagIndir.
return *(*unsafe.Pointer)(v.ptr) == nil
}
panic(&ValueError{"reflect.Value.IsNil", v.kind()})
}
当v的类型不是Chan, Func, Map, Ptr, UnsafePointer, Interface, Slice
中任何一个时,有panic
验证一下,执行下面一个代码
func main() {
var v interface{}
v = nil // 相比(*MyType)(nil),这个nil是没有类型的
// v = 1 // panic
// v = struct{}{} // panic
fmt.Println(reflect.ValueOf(v).IsNil())
}
果然panic
了
panic: reflect: call of reflect.Value.IsNil on zero Value
goroutine 1 [running]:
reflect.Value.IsNil(...)
C:/Program Files/Go/src/reflect/value.go:1440
main.main()
D:/User/space/golearn/main.go:130 +0x4e
总结
所以reflect.Valueof(v).IsNil
也并不是万能的,当一个interface被赋予nil
或值类型时,IsNil
就会panic
。
配合使用v == nil || reflect.ValueOf(v).IsNil()
可以在v不被赋予值类型时判断是否为nil