詳解Golang中interface{}的注意事項
interface {} 可以用于模擬多態(tài)
xdm 咱們寫一個簡單的例子,就舉動物的例子
寫一個 Animal 的接口,類似于 java 里面的抽象類 ,Animal 的接口 中有 2 個方案待實現(xiàn)
寫一個 Cat 來繼承 Animal , 實現(xiàn) Eat 方法和 Drink 方法
- 動物都有吃和喝的行為,小貓吃的行為是吃魚,小貓的喝的行為是喝可樂
- 最后在主函數(shù)中,使用父類的指針,來指向子類的實例化的一個子類地址
type Animal interface { Eat(string) string Drink(string) string } type Cat struct{} func (c *Cat) Eat(food string) string { if food != "fish" { return "i dislike" } else { return "i like" } } func (c *Cat) Drink(drink string) string { if drink == "coke" { return "i love" }else{ return "abandon" } } func main(){ var a Animal = &Cat{} fmt.Println(a.Eat("fish")) fmt.Println(a.Drink("water")) }
看到上述代碼,會不會有這樣的疑問,命名是 &Cat{}
是取地址的,為什么 var a Animal
不寫成指針呢?
這里需要注意,Animal 本身是 接口類型,自身就是一個指針
運行上述代碼查看效果
# go run main.go
i like
abandon
沒有毛病,小貓瞇愛吃魚,不愛喝水
interface{} 需要注意空和非空的情況
什么叫做空的 interface{} , 什么又叫做非空的 interface{} 呢?
咱們還是用上面的例子, 添加一個 testInterface 函數(shù)
,來實踐一下
func testInterface() Animal { var c *Cat return c } func main() { test := testInterface() if test == nil { fmt.Println("test is nil") } else { fmt.Println("test is not nil") } }
可以猜猜看,上面這個小案例會輸出什么結(jié)果
理論上來看,testInterface
函數(shù)中我們只是創(chuàng)建了一個 Cat 指針,并沒有賦值,因此默認是一個零值,因此會是一個 nil,那么 return 的時候,應(yīng)該也是 return nil 才對吧,因此按照代碼的邏輯來說應(yīng)該是輸出 test is nil
執(zhí)行上述代碼后,查看結(jié)果
# go run main.go
test is not nil
看到上面的結(jié)果,是不是覺得很奇怪,和自己的預(yù)期不一致
沒關(guān)系,之前的文章我們說到過,覺得一個技術(shù)點奇怪,不是我們所期望的效果,原因是我們對其原理不夠了解,不夠熟悉
現(xiàn)在先來回答一下上面的問題
空接口:意思是沒有方法的接口,interface{} 源碼中表示為 eface 結(jié)構(gòu)體
非空接口:表示有包含方法的接口 , interface{} 源碼中表示為 iface 結(jié)構(gòu)體
暫時先來直接介紹源碼中的結(jié)構(gòu)體
iface結(jié)構(gòu)體,非空
type iface struct { tab *itab data unsafe.Pointer } type itab struct { inter *interfacetype _type *_type link *itab hash uint32 // copy of _type.hash. Used for type switches. bad bool // type does not implement interface inhash bool // has this itab been added to hash? unused [2]byte fun [1]uintptr // variable sized }
tab
指的是具體的類型信息,是一個 itab 結(jié)構(gòu),結(jié)構(gòu)中成員如上,這里面包含的都是借口的關(guān)鍵信息,例如 hash 值 ,函數(shù)指針,等等,后續(xù)詳細剖析 interface{} 原理的時候再統(tǒng)一說
data
具體的數(shù)據(jù)信息
eface結(jié)構(gòu)體
type eface struct { _type *_type data unsafe.Pointer }
type _type struct { size uintptr // 表示的是 類型的大小 ptrdata uintptr // 值的是前綴指針的內(nèi)存大小 hash uint32 // 計算數(shù)據(jù)的 hash 值 tflag tflag align uint8 // 進行內(nèi)存對齊的 fieldalign uint8 kind uint8 alg *typeAlg gcdata *byte str nameOff ptrToThis typeOff }
_type
類型信息,和上面的 非空接口類似 , 這個_type 類型決定下面的 data 字段如何去解釋數(shù)據(jù)
data
具體的數(shù)據(jù)信息
看到這里,細心的 xdm 是不是就可以看出來,我們上面寫的 Animal 接口,其實是一個非空接口,因為里面有包含方法,所以他的底層是一個 iface 結(jié)構(gòu)體 ,非空接口
那么初始化的一個空指針 c ,實際上是 iface 結(jié)構(gòu)體里面的 data 字段為空而已,數(shù)據(jù)為空而已,但是 iface 這個結(jié)構(gòu)體自己不是空的,所以上述代碼走的邏輯是 test is not nil
這里順帶說一下,golang 中,還有哪些數(shù)據(jù)結(jié)構(gòu)是和 nil 比較是否為零值,這個點我們也可以看看源碼
// nil is a predeclared identifier representing the zero value for a // pointer, channel, func, interface, map, or slice type. var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
源碼中有說到,可以對 指針,通道,函數(shù),接口,map,切片類型使用 nil
好了,本次就到這里,知識點要用起來才有價值
以上就是詳解Golang中interface{}的注意事項的詳細內(nèi)容,更多關(guān)于Golang interface的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang import本地包和導入問題相關(guān)詳解
這篇文章主要介紹了Golang import本地包和導入問題相關(guān)詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-02-02Go項目實現(xiàn)優(yōu)雅關(guān)機與平滑重啟功能
無論是優(yōu)雅關(guān)機還是優(yōu)雅重啟歸根結(jié)底都是通過監(jiān)聽特定系統(tǒng)信號,然后執(zhí)行一定的邏輯處理保障當前系統(tǒng)正在處理的請求被正常處理后再關(guān)閉當前進程,這篇文章主要介紹了Go實現(xiàn)優(yōu)雅關(guān)機與平滑重啟 ,需要的朋友可以參考下2022-10-10Go?interface{}?轉(zhuǎn)切片類型的實現(xiàn)方法
本文主要介紹了Go?interface{}?轉(zhuǎn)切片類型的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02使用golang生成prometheus格式數(shù)據(jù)
Prometheus是一個開源的監(jiān)控系統(tǒng),擁有許多Advanced?Feature,本文將介紹Primetheus?client的使用,并基于golang生成prometheus格式數(shù)據(jù),希望對大家有所幫助2025-02-02