Golang 中 nil==nil 是對是錯?
via:https://medium.com/@shivi28/go-when-nil-nil-returns-true-a8a014abeffb
author:Shivani Singhal
這篇文章,我們將了解如何在 Go 中使用 == 操作符比較對象值。我們還將進一步研究某些場景下,該操作符的行為看起來像是一個錯誤,可實際是因為缺乏理解導(dǎo)致的。
看看下面的例子。
var a *string = nilvar b interface{} = afmt.Println("a == nil:", a == nil) // truefmt.Println("b == nil:", b == nil) // falsefmt.Println("a?==?b:",?a?==?b??)?//?true
結(jié)果對你來說奇怪嗎?
為了理解上面的例子,我們從一個簡單的例子開始。
var a int = 12var b int = 12c:= 12fmt.Println("a == b :", a == b) // truefmt.Println("a?==?c?:",?a?==?c)?//?true
這里的答案不難理解吧。
我們來改動一下這個例子。
var a *string = nilvar?b?interface{}?=?nilfmt.Println("a?==?nil:",?a?==?nil)?//?truefmt.Println("b?==?nil:",?b?==?nil)?//?truefmt.Println("a?==?b:",?a?==?b)?????//?false?(盡管a和b的值都為nil)
為了理解最后一種情況,我們深入研究一下。
在 Go 中,每個指針變量都有兩個與之相關(guān)的值,
。事實上,每個變量都必須指定一個類型,這就是為什么我們不能給未定義的變量賦空值。這就是為什么我們不能直接寫 x:=ni 的原因,如果我們沒有定義 x 的類型,我們會得到以下錯誤:
use?of?untyped?nil重新看這個問題,
var a *string = nil // a is <*string, nil>var b interface{} = nil // b isfmt.Println("a == nil:", a == nil) // truefmt.Println("b == nil:", b == nil) // truefmt.Println("a?==?b:",?a?==?b)????//?false?<*string,nil>!=
示例中,變量 a 實際表示?<*string,nil>。
interface{}?默認(rèn)類型是 nil,因此變量 b 實際是
在判斷 a==b 時,實際上是在比較 <*string,nil>?==?
現(xiàn)在回到我們第一個例子,
var?a?*string?=?nil?????//?a?is?<*string,?nil>var?b?interface{}?=?afmt.Println("a?==?nil:",?a?==?nil)?//true?(<*int,?nil>==<*int,?nil>)fmt.Println("b?==?nil:",?b?==?nil)?//false?(<*string,nil>==???? fmt.Println("a?==?b:",?a?==?b)?//?true
當(dāng)判斷 a==nil 時,== 運算符比較類型和值。在這里,左邊和右邊的值都是 nil,但是 nil 的類型是什么?
當(dāng) nil (硬編碼的值)與對象比較時,nil 的類型和與它比較的對象聲明的類型相同。
因此,在判斷 a==nil 的情況下,本質(zhì)上是判斷?<*string,nil> ==<*string,nil>。所以,結(jié)果為 true。
當(dāng)判斷 b==nil 時,右邊實際上是?<nil,nil>,而左邊 b 的類型是 interface{},它的默認(rèn)值是 nil。但是當(dāng)我們做了,
var?b?interface{}?=?a我們將 a 的值賦值給了 b,這就意味著 b 現(xiàn)在引用了 <*string,nil>。因此 當(dāng)判斷 b==nil 時,答案為 false。?
注意:var b interface{}?=a 不改變 b 變量的聲明類型。
總結(jié)
這個問題在開發(fā)過程中經(jīng)常出現(xiàn),例如下面這段代碼,我們可能會遇到這樣的錯誤。
var resp stringvar err errorresp, err = CallFunction()if err != nil{???//?如果?CallFunction?返回的類型和?err?不匹配,則執(zhí)行}func CallFunction() custom.Error{// 返回指針變量}
這里有更多的實驗[1]。
因此,最好檢查下被調(diào)用函數(shù)的返回類型和調(diào)用函數(shù)中接收變量的類型是否匹配。
附錄
推薦閱讀
