nil 在 Go語言中只能被賦值給指標和介面。介面在底層的實現有兩個部分:type 和 data。在原始碼中,顯式地將 nil 賦值給介面時,介面的 type 和 data 都將為 nil。此時,介面與 nil 值判斷是相等的。但如果將一個帶有型別的 nil 賦值給介面時,只有 data 為 nil,而 type 為 nil,此時,介面與 nil 判斷將不相等。
介面與 nil 不相等
下面程式碼使用 MyImplement() 實現 fmt 包中的 Stringer 介面,這個介面的定義如下:
type Stringer interface {
String() string
}
在 GetStringer() 函數中將返回這個介面。通過 *MyImplement 指標變數置為 nil 提供 GetStringer 的返回值。在 main() 中,判斷 GetStringer 與 nil 是否相等,程式碼如下:
package main
import "fmt"
// 定義一個結構體
type MyImplement struct{}
// 實現fmt.Stringer的String方法
func (m *MyImplement) String() string {
return "hi"
}
// 在函數中返回fmt.Stringer介面
func GetStringer() fmt.Stringer {
// 賦nil
var s *MyImplement = nil
// 返回變數
return s
}
func main() {
// 判斷返回值是否為nil
if GetStringer() == nil {
fmt.Println("GetStringer() == nil")
} else {
fmt.Println("GetStringer() != nil")
}
}
程式碼說明如下:
-
第 9 行,實現 fmt.Stringer 的 String() 方法。
-
第 21 行,s 變數此時被 fmt.Stringer 介面包裝後,實際型別為 *MyImplement,值為 nil 的介面。
-
第 27 行,使用 GetStringer() 的返回值與 nil 判斷時,雖然介面裡的 value 為 nil,但 type 帶有 *MyImplement 資訊,使用 == 判斷相等時,依然不為 nil。
發現 nil 型別值返回時直接返回 nil
為了避免這類誤判的問題,可以在函數返回時,發現帶有 nil 的指標時直接返回 nil,程式碼如下:
func GetStringer() fmt.Stringer {
var s *MyImplement = nil
if s == nil {
return nil
}
return s
}