大家好,我是煎魚。
最近在我們 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 催更。