关注公众号【爱发白日梦的后端】分享技术干货、读书笔记、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力!
很久之前发过一篇文章:《10个令人惊叹的Go语言技巧,让你的代码更加优雅》,这篇文章中第八点有一处错误的地方被认真的读者发现了:
于是我有空之后,立马重新看了那篇文章的内容,确实是存在读者所说的问题。
问题就在于下面这句话,文章也是有列出的:
即使接口持有的值为?
nil
,也不意味着接口本身为?nil
。
但是在执行以下语句的时候,是有可能报 panic
的:
return reflect.ValueOf(x).IsNil()
而输出也是非常明显的指出错误:
panic: reflect: call of reflect.Value.IsNil on int Value
因为不可 nil
的 interface
是不能使用 reflect.Value.IsNil
方法。
那么问题就很好解决了。
我们在执行 reflect.Value.IsNil
方法之前,进行一次判断是否为指针即可:
func IsNil(x interface{}) bool {
if x == nil {
return true
}
rv := reflect.ValueOf(x)
return rv.Kind() == reflect.Ptr && rv.IsNil()
}
重点在于 rv.Kind() == reflect.Ptr && rv.IsNil()
这段代码。
这段代码的作用:
x
的类型是否为指针。x
的值是否真的为 nil
。下面我们使用几种常见的数据类型来进行测试:
func IsNil(x interface{}) bool {
if x == nil {
return true
}
rv := reflect.ValueOf(x)
return rv.Kind() == reflect.Ptr && rv.IsNil()
}
func main() {
fmt.Printf("int IsNil: %t\n", IsNil(returnInt()))
fmt.Printf("intPtr IsNil: %t\n", IsNil(returnIntPtr()))
fmt.Printf("slice IsNil: %t\n", IsNil(returnSlice()))
fmt.Printf("map IsNil: %t\n", IsNil(returnMap()))
fmt.Printf("interface IsNil: %t\n", IsNil(returnInterface()))
fmt.Printf("structPtr IsNil: %t\n", IsNil(returnStructPtr()))
}
func returnInt() interface{} {
var value int
return value
}
func returnIntPtr() interface{} {
var value *int
return value
}
func returnSlice() interface{} {
var value []string
return value
}
func returnMap() interface{} {
var value map[string]struct{}
return value
}
func returnInterface() interface{} {
var value interface{}
return value
}
type People struct {
Name string
}
func returnStructPtr() interface{} {
var value *People
return value
}
我们先后使用了 int
、*int
、slice
、map
、interface{}
、自定义结构体
来测试此 IsNil
方法。运行程序输出为:
int IsNil: false
intPtr IsNil: true
slice IsNil: false
map IsNil: false
interface IsNil: true
structPtr IsNil: true
从测试结果来看,目前是符合我们对此方法的定位的。