在golang中如何正確判斷接口是否為nil


本文主要來分析一下在golang中,如何判斷interface是否為nil,以及相關注意事項。

正常情況下,我們聲明一個interface類型的變量,默認值將會返回nil,以golang自帶的io.Writer為例

var writer io.Writer
fmt.Printf("writer is nil => %t\n", writer == nil)

https://img2020.cnblogs.com/blog/846715/202112/846715-20211216023856151-1746640308.png

當然我們也可以用具體的實現結構來定義一個指針變量,它的默認值也是nil

var bufWriter *bufio.Writer
fmt.Printf("bufWriter is nil => %t\n", bufWriter == nil)

輸出結果與上述的一樣

https://img2020.cnblogs.com/blog/846715/202112/846715-20211216024235931-92943971.png

以上的輸出都是我們預期中的結果。

在實際開發中我們經常會碰到從某個函數中返回interface實例的情況,例如

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)

此時我們的返回值是否仍舊與預期中的一致呢?

https://img2020.cnblogs.com/blog/846715/202112/846715-20211216024654462-1526563179.png

結果好像跟我們預想的有一些不太一樣,因為在匿名函數中返回的是一個定義但是還未賦值的指針類型,並且在函數內部判斷時,已經輸出該變量為nil了,但是當我們在外部接收到這個值的時候,似乎變成非nil狀態了

看着好像有一些詭異

那么,讓我們來實際調用一下這個接口的函數試試

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"))
}

可以看到,我們明明已經進行非空判斷了,結果還是panic了

https://img2020.cnblogs.com/blog/846715/202112/846715-20211216025157991-1764224303.png

這是怎么回事呢?

其實當我們使用==直接將一個interface與nil進行比較的時候,golang會對interface的類型和值分別進行判斷。
如果兩者都為nil,在與nil直接比較時才會返回true,否則直接返回false。所以上面代碼中interface與nil進行比較時返回的是false,因為此時interface變量的值是nil,但是他的類型不是nil,已經有了明確的實現類型,即bufio.Writer。因而當我們調用這個interface的函數成員時,就會直接panic。

所以在實際開發中,當interface類型的返回值已經明確為nil時,應該直接返回nil,而不是具體實現結構的未賦值空指針

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")
}

可以看到,此時我們可以正確判斷interface是否為nil了

https://img2020.cnblogs.com/blog/846715/202112/846715-20211216025122909-2032874324.png

那么有沒有辦法去判斷interface的真實值是否為nil呢?

當然可以,答案就是使用反射,示例如下:

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())

可以看到,當我們通過反射來判斷是否為nil時,獲取到了與我們預期一樣的結果

https://img2020.cnblogs.com/blog/846715/202112/846715-20211216025822313-2146488876.png

參考資料

Why is my nil error value not equal to nil?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM