golang sql繫結變數_記錄一個golang的nil型別有意思的case
技術標籤:golang sql繫結變數
背景
定位線上服務panic的問題,捕獲的panic棧日誌顯示某一行出現nil指標操作,很常見的一個panic問題,去定位到專案中該行程式碼,發現有好兩處對指標的操作,類似如下的操作
type Item struct { A int } func (i *Item)Add(number int) int{ return number + 1 } func main (){ ..... var item *Item if item.Add(number) > 10 && item.A > 20 { .... } }
本以為很簡單,item為空指標,不能對其進行操作。但是,突然發現一個有意思的現象,item.Add函式竟然執行成功了,導致panic的原因是後面的item.A。如果你看到這裡,覺得這不是大家都知道的事情嗎,那就不用往下看了。
原因探索
其實仔細思考下,原因也很簡單,item雖然值為nil,但是它的型別是Item,Item型別綁定了Add函式,而且Add並沒有方位物件的任何變數,只是單純的對引數做了加法返回,而導致panic的item.A 是因為訪問了物件,接下來我們通過實際操作,一一驗證我們的想法。
驗證
- 程式碼
package main import ( "fmt" "reflect" ) type AA struct { x int } func (this *AA) a() { fmt.Println("你好") } func main() { var aa *AA fmt.Println(reflect.TypeOf(aa),reflect.TypeOf(nil)) fmt.Println(reflect.ValueOf(aa),reflect.ValueOf(nil)) aa.a() }
執行結果
結論
我們通過反射,看出結構體空指標與普通的nil還是不同的,結構體指標的型別是可以獲取到的,相應的它對應的函式應該可以執行。
- 程式碼
package main import ( "fmt" "reflect" ) type A interface { a() } type AA struct { x int } func (this *AA) a() { fmt.Println("你好") } func main() { var aa A fmt.Println(reflect.TypeOf(aa),reflect.TypeOf(nil)) fmt.Println(reflect.ValueOf(aa),reflect.ValueOf(nil)) aa.a() }
執行結果
結論
這次我們命名了一個介面,並且建立了一個空的介面變數,發現它的型別和value竟然與真正的nil完全相同,至於為什麼,可能需要單獨寫一篇有關interface的結構的文章來解釋。但是在這裡我們大致可以理解,空的介面變數,與實現該介面的結構體的空指標是完全不同的。結構體空指標應該是在某個地方存著該結構體的函式變數,而空的介面變數對應的函式指標是nil。
- 程式碼
package main
import (
"fmt"
)
type A interface {
a()
}
type AA struct {
x int
}
func (this *AA) a() {
fmt.Println("你好")
}
func main() {
var A *AA
A.x = 1
}
執行結果
結論
這就比較明顯了,雖然空的結構體指標可以呼叫對應的函式,但是絕對不能訪問其內部欄位。
我們在來看一個比較有意思的事情。
- 程式碼
package main
import (
"fmt"
)
type A interface {
a()
}
type AA struct {
x int
}
func (this *AA) a() {
fmt.Println("你好")
}
func main() {
a := (*AA)(nil)
a.a()
}
執行結果
結論
其實也比較好理解,我們把一個空指標,強轉成一個*AA型別,必然給它附上了對應的函式指標,它就跟純nil不太一樣了。
最後
其實,在實驗的過程中產生了很多的疑問,我會在後續的文章給出一一解答。
- golang 的interface底層是什麼結構?(其實有iface與eface兩種,區別為是否包含函式)
- golang的結構體與interface又是什麼聯絡,結構體繫結函式後就可以作為interface,golang的編譯器在繫結函式的時候做了什麼?
- golang的結構體的函式存在哪裡,函式呼叫的時候是如何找到的?
- golang的結構體的函式繫結有值繫結與指標繫結,區別是什麼?