如何优雅的判断变量是否为空呢?如下两个方法即可(先给着急用答案)
func IsNil(val interface{}) bool {
if nil == val {
return true
}
return reflect.ValueOf(val).IsNil()
}
func IsNotNil(val interface{}) bool {
return !IsNil(val)
}
nil
判断在 go
的日常开发编码中是比较常见的,不管是错误返回,亦是未初始化的 Slice
、Map
、Chan
,Pointer
、Func
、interface{}
都会涉及到判空的场景。
func main() {
var sli []int
fmt.Println("slice:", sli == nil, reflect.TypeOf(sli).Kind(), reflect.ValueOf(sli).IsValid())
var ma map[string]int
fmt.Println("map:", ma == nil, reflect.TypeOf(ma).Kind(), reflect.ValueOf(ma).IsValid())
var ch chan int
fmt.Println("chan:", ch == nil, reflect.TypeOf(ch).Kind(), reflect.ValueOf(ch).IsValid())
var user *struct {
Name string
Age uint8
}
fmt.Println("pointer:", user == nil, reflect.TypeOf(user).Kind(), reflect.ValueOf(user).IsValid())
var fun func() string
fmt.Println("func:", fun == nil, reflect.TypeOf(fun).Kind(), reflect.ValueOf(fun).IsValid())
var err error
//fmt.Println(err == nil, errors.Is(err, nil))
fmt.Println("error:", err == nil, reflect.TypeOf(err), reflect.ValueOf(err).IsValid())
var itf interface{}
fmt.Println("interface{}:", itf == nil, reflect.TypeOf(itf), reflect.ValueOf(itf))
}
slice: true slice true
map: true map true
chan: true chan true
pointer: true ptr true
func: true func true
error: true <nil> false
interface{}: true <nil> <invalid reflect.Value>
注解说明一下
func IsNil(val interface{}) bool {
// type && value 都为 nil 的场景 nil error / interface{}
// type nil 则 value 必 nil, 此时可直接与 nil 比较
// 等价于 nil == reflect.TypeOf(val)
if nil == val {
return true
}
// 其它类型的变量 需要看 value
return reflect.ValueOf(val).IsNil()
}
func IsNotNil(val interface{}) bool {
return !IsNil(val)
}
需要注意的是:为了兼容所有类型的变量的值
判空(我们的目的就是判值
是否为空),所以参数类型为 interface{}
,但 ”空接口“变量
并不能简单的使用 nil == val
来判断是否为空,因为 interface{}
有两个属性 type
和 value
。只有当 type
为 nil
&& value
为 nil
时,才可以直接使用 nil == val
来做判空,而非 interface{}
类型的变量转为此类型时,type
会被设为对应的数据原型,故此时我们需要进一步判断 value
是否为空。
例如:
- 当我们将一个
空指针 var p *int
传值给interface{}
时会得被转为如下状态:{type: pointer, value: nil}
,此时因为type
为pointer
,所以直接与nil
等值比较会得false
,应该进一步比较value
是否为nil
来得到期望结果,故需要通过reflect
获取value
进行值的判空。 error
类型实为interface { Error() string }
,当声明了一个变量var err error
时,其实值还是一个{type: nil,value: nil}
的interface{}
,可以使用reflect.Typeof(err), reflect.Valueof(err)
来具体查看。
引申:
当我们使用 reflect
来反射解析变量获取 Type
和 Value
时,一定要先判断 reflect.Typeof(val)
或 reflect.Valueof(val).IsValid()
或 == nil
来判断是否为 nil
值的 interface{}
,如果是则没有反射的必要了。
func main() {
var val error
if nil == val {
fmt.Println("val is nil:", true)
}
if nil == reflect.Typeof(val) {
fmt.Println("val is nil:", true)
}
if !reflect.Valueof(val).IsValid() {
fmt.Println("val is nil:", true)
}
if reflect.Valueof(val).IsValid() {
fmt.Println("val is nil:", reflect.Valueof(val).IsNil())
fmt.Println("val is zero:", reflect.Valueof(val).IsZero())
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。