golang 判空的坑
var a *int
fmt.Println((interface{}(a)) != nil )
//Output: true
带类型的指针 转成 interface{} 后 无法在判断是否为空指针, 解决的方法
- 反射判断指针是否为空
- 通过unsafe 的方式
如果有类型的指针转为了 interface{} 之后, 其实现原理是 go 用 一个 eface的结构体表示 interface{} 类型, eface 有两个字段,一个是type表示类型,一个是 unsafe.Pointer 用来表示指针指向的地址, 可以用 unsafe.Pointer 的方式转回来,然后单独判断 interface{} 值指向的地址即可。
// 值判空
func IsValueNil(b interface{}) bool {
if b == nil {
return true
}
// 判断值是否为空
type eface struct {
v int64
ptr unsafe.Pointer
}
efaceptr := (*eface)(unsafe.Pointer(&b))
if efaceptr == nil {
return true
}
// ok := efaceptr == nil || uintptr(efaceptr.ptr) == 0
return uintptr(efaceptr.ptr) == 0x0
}
func isValueNil2(p interface{}) bool {
if p == nil {
return true
}
valueof := reflect.ValueOf(p)
if valueof.Kind() != reflect.Ptr {
return false //is not nil
}
return valueof.IsNil()
}
func Example_nil() {
type user struct{}
var target []interface{}
target = append(target, (*int)(nil))
target = append(target, (*string)(nil))
target = append(target, (*interface{})(nil))
target = append(target, (*user)(nil))
target = append(target, (nil))
for _, v := range target {
isNil := IsValueNil(v)
if !isNil {
panic("is nil pointer")
}
if isNil != isValueNil2(v) {
panic("no match ")
}
}
var b *int
//空指针转 interface{} 后无法判空
fmt.Println("ok all is nil", (interface{}(b)) != nil)
// Output: ok all is nil true
}