您的位置 首页 golang

Go语言interface底层实现

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的具体结构是:

一共有两个属性构成,一个是类型信息_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的整体结构是:

对于没有方法的interface赋值后的内部结构是怎样的呢?

可以先看段代码:

 import  (
	"fmt"
	"strconv"
)
type  Binary  uint64
func main() {
	b := Binary(200)
	any := (interface{})(b)
	fmt.Println(any)
}
 

输出200,赋值后的结构图是这样的:

对于将不同类型转化成type万能结构的方法,是运行时的convT2E方法,在runtime包中。

以上,是对于没有方法的接口说明。

对于包含方法的函数,用到的是另外的一种结构,叫iface

iface

所有包含方法的接口,都会使用iface结构。包含方法的接口就是一下这种最常见,最普通的接口:

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语言interface底层实现

文章地址:https://www.zhihuclub.com/86543.shtml

关于作者: 智云科技

热门文章

网站地图