Go 面試官:值爲 nil 爲什麼不等於 nil ?

小明同學去面試被問到了這麼一個面試題,請看代碼:

var f func()
var a *struct{}

list := []interface{}{f, a}
for _, item := range list {
 if item == nil {
  fmt.Println("nil")
 }
}

請問輸出結果是啥?

可能很多同學,會認爲結果是輸出兩個 nil。

爲什麼呢?

因爲 f 和 a 都沒初始化,都是 nil,所以循環遍歷後肯定也是 nil。

如果你的答案也是這樣,那就掉進坑裏了。

答案是,啥都不會輸出!

且聽我慢慢給你分析:

一、變量的值和類型

我們先來打印下這兩個值:

var f func()
var a *struct{}
fmt.Println(f, a)

// 輸出結果
<nil> <nil>

我們這樣打印其實是打印的是他的值,是 nil 沒錯的。

但是類型不是 nil。

我們可以這樣打印他類型:

var f func()
var a *struct{}
fmt.Printf("%T,%T \n", f, a)

// 輸出結果
func(),*struct {}

二、if 判 nil 含有對類型的判斷

當我們從 interface  裏面把對象取出來後,使用 if 進行判斷,他不單單的比較的是值,還有類型。

看下這段代碼:

var f func()
var a *struct{}

list := []interface{}{f, a, nil}
 for _, item := range list {
  fmt.Println("item=", item)
  fmt.Printf("item type: %T \n", item)
  if item == nil {
   fmt.Println("item == nil")
  }
  fmt.Println("----")
 }
}

現在看下運行結果:

$ go run main.go 
item= <nil>
item type: func() 
----
item= <nil>
item type: *struct {} 
----
item= <nil>
item type: <nil> 
item == nil
----

你會發現之後最後 nil 的判斷是通過的,前面兩個判斷都不通過。

三、怎麼判斷值是否爲 nil

我們在寫代碼時,最好是儘量避免這種代碼,如果硬要這麼寫,那我們可以通過以下兩種常見方式判 nil。

1、斷言

list := []interface{}{f, a}
for _, item := range list {
 if v, ok := item.(func()); ok && v == nil {
  fmt.Println("item is nil")
 }
 if v, ok := item.(*struct{}); ok && v == nil {
  fmt.Println("item is nil")
 }
}

2、反射

list := []interface{}{f, a}
for _, item := range list {
 if reflect.ValueOf(item).IsNil() {
  fmt.Println("item is nil")
 }
}

你學廢了麼?

歡迎加入我們的交流羣一起討論。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/qPrfMgPVkl1gSLxR690zgw