Go語言介面的nil判斷

2020-07-16 10:05:22
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
}