Go-接口實現(xiàn)原理
接口的底層結(jié)構(gòu)
eface和iface
??eface和iface都是描述接口的數(shù)據(jù)結(jié)構(gòu),區(qū)別在于iface描述的接口包含方法、而eface描述的接口不包含方法
eface的數(shù)據(jù)結(jié)構(gòu)
type eface struct {
_type *_type //實體類型
data unsafe.Pointer //具體的值
}
eface主要包含實體類型_type指針和指向具體值的指針data,
-
_type描述了實體類型包括內(nèi)存大小、對齊方式等等,所有類型均可解釋為_type -
data存儲了數(shù)據(jù)的指針,即使是對于數(shù)字、字符串這樣的字面值也是通過額外分配空間取指針的
iface的數(shù)據(jù)結(jié)構(gòu)
type iface struct {
tab *itab
data unsafe.Pointer
}
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}

iface結(jié)構(gòu)圖.png
在iface中存儲的是一個itab指針和一個指向數(shù)據(jù)的指針,itab中:
-
_type依舊描述了實體類型包括內(nèi)存大小、對齊方式等數(shù)據(jù) -
inter則描述了接口自身的信息,其中的mhdr字段包含了接口所定義的方法 -
fun其實是一個動態(tài)數(shù)組,雖然聲明時是固定大小為1,但在使用時會直接通過fun指針獲取其中的數(shù)據(jù),類似于c語言中的不定長結(jié)構(gòu)體
值接收者和指針接受者
package main
type Person struct {
age int
}
func (p Person) howOld() int {
return p.age
}
func (p *Person) growUp() {
p.age += 1
}
func main() {
p1 := Person{}
p2 := &Person{}
p1.howOld()
p1.growUp()
p2.howOld()
p2.growUp()
}
howOld是值接收者、growUp是指針接者,對于普通的函數(shù)調(diào)用而言在使用者go內(nèi)部做了兼容可以互相調(diào)用
但是在接口中這是不兼容的,指針類型、值類型賦值給接口其生成的函數(shù)集是不一樣的
函數(shù)集
| 值類型 | 函數(shù)集 |
|---|---|
值(T)
|
(t T) |
指針(*T)
|
(t T)和 (t *T)
|
原因很簡單:對于有一些值是無法取到指針的,比如數(shù)字、字符串的字面值