Go語言interface底層實現

Go的interface源碼在Golang源碼的runtime目錄中。 Go在不一樣版本之間的interface結構可能會有所不一樣,可是,總體的結構是不會改變的,此文章用的Go版本是1.11。微信

Go的interface是由兩種類型來實現的:ifaceeface。 其中,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的具體結構是:

在這裏插入圖片描述

itabiface不一樣於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的公共描述,相似的還有maptypearraytypechantype...其都是各個結構的公共描述,能夠理解爲一種外在的表現信息。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

更多精彩內容,請關注個人微信公衆號 互聯網技術窩 或者加微信共同探討交流:

相關文章
相關標籤/搜索