為什麼 Go 裡值為 nil 可以呼叫函式?

煎魚發表於2021-12-27

大家好,我是煎魚。

最近在我們 Go 的技術交流群裡,有一個小夥伴提了一個程式方面的問題,還挺有意思的,分享給大家。

示例

示例程式如下:

type T struct{}

func (t *T) Hello() string {
    if t == nil {
        fmt.Println("腦子進煎魚了")
        return ""
    }

    return "煎魚進腦子了"
}

func main() {
    var t *T
    t.Hello()

這段程式的執行結果是什麼?

從程式的分析來看,變數 t 並沒有初始化,只是宣告瞭型別。然後就直接呼叫了 Hello 方法,像是 nil 呼叫函式,理論上應該出現恐慌(panic)。

執行結果是:

panic: runtime error: invalid memory address or nil pointer dereference

對不對呢?

顯然,真正的執行結果是:

腦子進煎魚了

請你思考一下,想想這是為什麼?

為什麼

問題的原因是:很多小夥伴認為變數 t 的值都是 nil 了,不應該還能呼叫到才對。

更抽象化來講,就是 ”程式是如何檢查物件指標來尋找和排程所需函式“。

實際上,在 Go 中,表示式 Expression.Name 的語法,所呼叫的函式完全由 Expression 的型別決定。

其呼叫函式的指向不是由該表示式的特定執行時值來決定,包括我們前面所提到的 nil。

具體如下:

func (p *Sometype) Somemethod (firstArg int) {}

本質上是:

func SometypeSomemethod(p *Sometype, firstArg int) {}

這麼一看,其實大家應該都明白了。

上述入參 p *Sometype 是有具體上下文型別的,自然而然也就能呼叫到相應的方法。如果是沒有任何上下文型別的,例如:nil.Somemethod 方法來呼叫,那肯定就是無法執行的。

與值是不是 nil,是什麼,沒有太多直接的影響。只要有預期型別的上下文就可以了。

總結

今天給大家分享了一個 Go 語言裡面的一個小細節,平時可能很多人沒注意到,畢竟 IDE 也會標黃,會避開這個問題點。

在理解 Go 的設計和思考上,我們是需要清晰其背後的原因和邏輯的,也就是型別決定其呼叫,而不是值(容易誤判)。

你有沒有遇到過其它的細節問題呢,歡迎交流:)

若有任何疑問歡迎評論區反饋和交流,最好的關係是互相成就,各位的點贊就是煎魚創作的最大動力,感謝支援。

文章持續更新,可以微信搜【腦子進煎魚了】閱讀,本文 GitHub github.com/eddycjy/blog 已收錄,學習 Go 語言可以看 Go 學習地圖和路線,歡迎 Star 催更。

相關文章