如何優雅的判斷變數是否為空呢?如下兩個方法即可(先給著急用答案)
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())
}
}