本文主要來分析一下在golang中费变,如何判斷interface是否為nil粥帚,以及相關(guān)注意事項(xiàng)。
正常情況下祟剔,我們聲明一個(gè)interface類型的變量隔躲,默認(rèn)值將會(huì)返回nil,以golang自帶的io.Writer
為例
var writer io.Writer
fmt.Printf("writer is nil => %t\n", writer == nil)
當(dāng)然我們也可以用具體的實(shí)現(xiàn)結(jié)構(gòu)來定義一個(gè)指針變量物延,它的默認(rèn)值也是nil
var bufWriter *bufio.Writer
fmt.Printf("bufWriter is nil => %t\n", bufWriter == nil)
輸出結(jié)果與上述的一樣
以上的輸出都是我們預(yù)期中的結(jié)果宣旱。
在實(shí)際開發(fā)中我們經(jīng)常會(huì)碰到從某個(gè)函數(shù)中返回interface實(shí)例的情況,例如
bufWriter := func() io.Writer {
var w *bufio.Writer
fmt.Printf("w is nil => %t\n", w == nil)
return w
}()
fmt.Printf("bufWriter is nil => %t\n", bufWriter == nil)
此時(shí)我們的返回值是否仍舊與預(yù)期中的一致呢叛薯?
結(jié)果好像跟我們預(yù)想的有一些不太一樣浑吟,因?yàn)樵谀涿瘮?shù)中返回的是一個(gè)定義但是還未賦值的指針類型,并且在函數(shù)內(nèi)部判斷時(shí)耗溜,已經(jīng)輸出該變量為nil了组力,但是當(dāng)我們在外部接收到這個(gè)值的時(shí)候,似乎變成非nil狀態(tài)了
看著好像有一些詭異
那么抖拴,讓我們來實(shí)際調(diào)用一下這個(gè)接口的函數(shù)試試
bufWriter := func() io.Writer {
var w *bufio.Writer
fmt.Printf("w is nil => %t\n", w == nil)
return w
}()
if bufWriter != nil {
bufWriter.Write([]byte("golang"))
}
可以看到燎字,我們明明已經(jīng)進(jìn)行非空判斷了,結(jié)果還是panic了
這是怎么回事呢?
其實(shí)當(dāng)我們使用==直接將一個(gè)interface與nil進(jìn)行比較的時(shí)候轩触,golang會(huì)對(duì)interface的類型和值分別進(jìn)行判斷。
如果兩者都為nil家夺,在與nil直接比較時(shí)才會(huì)返回true脱柱,否則直接返回false。所以上面代碼中interface與nil進(jìn)行比較時(shí)返回的是false拉馋,因?yàn)榇藭r(shí)interface變量的值是nil榨为,但是他的類型不是nil,已經(jīng)有了明確的實(shí)現(xiàn)類型煌茴,即bufio.Writer
随闺。因而當(dāng)我們調(diào)用這個(gè)interface的函數(shù)成員時(shí),就會(huì)直接panic蔓腐。
所以在實(shí)際開發(fā)中矩乐,當(dāng)interface類型的返回值已經(jīng)明確為nil時(shí),應(yīng)該直接返回nil回论,而不是具體實(shí)現(xiàn)結(jié)構(gòu)的未賦值空指針
bufWriter := func() io.Writer {
var w *bufio.Writer
if w == nil {
return nil
}
return w
}()
if bufWriter != nil {
bufWriter.Write([]byte("golang"))
} else {
fmt.Println("bufWriter is nil")
}
可以看到散罕,此時(shí)我們可以正確判斷interface是否為nil了
那么有沒有辦法去判斷interface的真實(shí)值是否為nil呢?
當(dāng)然可以傀蓉,答案就是使用反射欧漱,示例如下:
bufWriter := func() io.Writer {
var w *bufio.Writer
fmt.Printf("w is nil => %t\n", w == nil)
return w
}()
fmt.Printf("bufWriter is nil => %t\n", bufWriter == nil)
fmt.Printf("IsNil => bufWriter is nil => %t\n", reflect.ValueOf(bufWriter).IsNil())
可以看到,當(dāng)我們通過反射來判斷是否為nil時(shí)葬燎,獲取到了與我們預(yù)期一樣的結(jié)果