如何优雅的判断变量是否为空呢?如下两个方法即可(先给着急用答案)
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) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。