Go的interface源碼在Golang源碼的runtime
目錄中。 Go在不一樣版本之間的interface結構可能會有所不一樣,可是,總體的結構是不會改變的,此文章用的Go版本是1.11。微信
Go的interface是由兩種類型來實現的:iface
和eface
。 其中,iface
表示的是包含方法的interface,例如:數據結構
type Person interface {
Print()
}
複製代碼
而eface
表明的是不包含方法的interface,即函數
type Person interface {}
複製代碼
或者ui
var person interface{} = xxxx實體
複製代碼
eface
eface
的具體結構是: spa
_type
,一個是數據信息。 其中,
_type
能夠認爲是Go語言中全部類型的公共描述,Go語言中幾乎全部的數據結構均可以抽象成
_type
,是全部類型的表現,能夠說是萬能類型,
data
是指向具體數據的指針。
type
的具體代碼爲:3d
type _type struct {
size uintptr
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32
tflag tflag
align uint8
fieldalign uint8
kind uint8
alg *typeAlg
// gcdata stores the GC type data for the garbage collector.
// If the KindGCProg bit is set in kind, gcdata is a GC program.
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
gcdata *byte
str nameOff
ptrToThis typeOff
}
複製代碼
eface
的總體結構是: 指針
對於沒有方法的interface賦值後的內部結構是怎樣的呢? 能夠先看段代碼:code
import (
"fmt"
"strconv"
)
type Binary uint64
func main() {
b := Binary(200)
any := (interface{})(b)
fmt.Println(any)
}
複製代碼
輸出200,賦值後的結構圖是這樣的: orm
type
萬能結構的方法,是運行時的
convT2E
方法,在
runtime
包中。 以上,是對於沒有方法的接口說明。 對於包含方法的函數,用到的是另外的一種結構,叫
iface
iface
全部包含方法的接口,都會使用iface
結構。包含方法的接口就是一下這種最多見,最普通的接口:cdn
type Person interface {
Print()
}
複製代碼
iface
的源代碼是:
type iface struct {
tab *itab
data unsafe.Pointer
}
複製代碼
iface
的具體結構是:
itab
是iface
不一樣於eface
比較關鍵的數據結構。其可包含兩部分:一部分是肯定惟一的包含方法的interface的具體結構類型,一部分是指向具體方法集的指針。 具體結構爲:
itab
的源代碼是:
type itab struct {
inter *interfacetype //此屬性用於定位到具體interface
_type *_type //此屬性用於定位到具體interface
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.
}
複製代碼
屬性interfacetype
相似於_type
,其做用就是interface的公共描述,相似的還有maptype
、arraytype
、chantype
...其都是各個結構的公共描述,能夠理解爲一種外在的表現信息。interfacetype
源碼以下:
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
type imethod struct {
name nameOff
ityp typeOff
}
複製代碼
iface
的總體結構爲:
對於含有方法的interface賦值後的內部結構是怎樣的呢? 一下代碼運行後
package main
import (
"fmt"
"strconv"
)
type Binary uint64
func (i Binary) String() string {
return strconv.FormatUint(i.Get(), 10)
}
func (i Binary) Get() uint64 {
return uint64(i)
}
func main() {
b := Binary(200)
any := fmt.Stringer(b)
fmt.Println(any)
}
複製代碼
首先,要知道代碼運行結果爲:200。 其次,瞭解到fmt.Stringer
是一個包含String
方法的接口。
type Stringer interface {
String() string
}
複製代碼
最後,賦值後接口Stringer
的內部結構爲:
對於將不一樣類型轉化成itable中type(Binary)
的方法,是運行時的convT2I
方法,在runtime
包中。
參考文獻:
《Go in action》
https://research.swtch.com/interfaces
https://juejin.im/entry/5a7d08d3f265da4e865a6200
互聯網技術窩
或者加微信共同探討交流: