Go的interface原始碼在Golang原始碼的runtime
目錄中。
Go在不同版本之間的interface結構可能會有所不同,但是,整體的結構是不會改變的,此文章用的Go版本是1.11。
Go的interface是由兩種型別來實現的:iface
和eface
。
其中,iface
表示的是包含方法的interface,例如:
type Person interface {
Print()
}
複製程式碼
而eface
代表的是不包含方法的interface,即
type Person interface {}
複製程式碼
或者
var person interface{} = xxxx實體
複製程式碼
eface
eface
的具體結構是:
![在這裡插入圖片描述](https://i.iter01.com/images/a45e32291e561b7fdf70200db99ce4e55d8fc04aa6016882f569645106aa7bcf.jpg)
_type
,一個是資料資訊。
其中,_type
可以認為是Go語言中所有型別的公共描述,Go語言中幾乎所有的資料結構都可以抽象成_type
,是所有型別的表現,可以說是萬能型別,
data
是指向具體資料的指標。
type
的具體程式碼為:
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
的整體結構是:
![在這裡插入圖片描述](https://i.iter01.com/images/8be03c99d380db1dc821a9892c9b7ccae90cde0cd6e7286a02e1875617471b60.jpg)
對於沒有方法的interface賦值後的內部結構是怎樣的呢? 可以先看段程式碼:
import (
"fmt"
"strconv"
)
type Binary uint64
func main() {
b := Binary(200)
any := (interface{})(b)
fmt.Println(any)
}
複製程式碼
輸出200,賦值後的結構圖是這樣的:
![在這裡插入圖片描述](https://i.iter01.com/images/87043b91051546171f19ce4cac503012748f00b05d54786d8185ad6f60fc8783.jpg)
type
萬能結構的方法,是執行時的convT2E
方法,在runtime
包中。
以上,是對於沒有方法的介面說明。
對於包含方法的函式,用到的是另外的一種結構,叫iface
iface
所有包含方法的介面,都會使用iface
結構。包含方法的介面就是一下這種最常見,最普通的介面:
type Person interface {
Print()
}
複製程式碼
iface
的原始碼是:
type iface struct {
tab *itab
data unsafe.Pointer
}
複製程式碼
iface
的具體結構是:
![在這裡插入圖片描述](https://i.iter01.com/images/35cfcf4f309a10cf94b9223988d641d2743addba4221dff2c53492d097af3b6e.png)
itab
是iface
不同於eface
比較關鍵的資料結構。其可包含兩部分:一部分是確定唯一的包含方法的interface的具體結構型別,一部分是指向具體方法集的指標。
具體結構為:
![在這裡插入圖片描述](https://i.iter01.com/images/089f1e93d9d86c8436d1a93e1406216d83e8289e62db262f519077c5cd6d00b2.png)
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
的整體結構為:
![在這裡插入圖片描述](https://i.iter01.com/images/449b6783fac9360428af61a202fb6f0205c0744617f89bafb78f6ec361eaabc5.jpg)
對於含有方法的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
的內部結構為:
![在這裡插入圖片描述](https://i.iter01.com/images/899776e788b887bc7a29d7b53a084f350aca3135db2c0bbc4802944312b5f32d.jpg)
對於將不同型別轉化成itable中type(Binary)
的方法,是執行時的convT2I
方法,在runtime
包中。
參考文獻:
《Go in action》
https://research.swtch.com/interfaces
https://juejin.im/entry/5a7d08d3f265da4e865a6200
更多精彩內容,請關注我的微信公眾號 網際網路技術窩
或者加微信共同探討交流:
![Go語言interface底層實現](https://i.iter01.com/images/07e0cef08d2cb435cabdb1f64d76a4f3ce79dfe321cc33b37dac18a9892eaad7.jpg)