go 接口 | | 青训营笔记

82 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 13 天

在 Go 语言中,接口的底层数据结构在运行时一共分为两类结构体(struct),分别是:

  • runtime.eface 结构体:表示不包含任何方法的空接口,也称为 empty interface。
  • runtime.iface 结构体:表示包含方法的接口。

runtime.eface

type eface struct {
	_type *_type
	data  unsafe.Pointer
}

其表示不包含任何方法的空接口。在结构上来讲 eface 非常简单,就两个属性,分别是 _type 和 data 属性,分别代表底层的指向的类型信息和指向的值信息指针。

再进一步到 type 属性里看看,其包含的类型信息更多:

type _type struct {
	size       uintptr
	ptrdata    uintptr 
	hash       uint32
	tflag      tflag
	align      uint8
	fieldAlign uint8
	kind       uint8
	equal func(unsafe.Pointer, unsafe.Pointer) bool
	gcdata    *byte
	str       nameOff
	ptrToThis typeOff
}
  • size:类型的大小。
  • ptrdata:包含所有指针的内存前缀的大小。
  • hash:类型的 hash 值。此处提前计算好,可以避免在哈希表中计算。
  • tflag:额外的类型信息标志。此处为类型的 flag 标志,主要用于反射。
  • align:对应变量与该类型的内存对齐大小。
  • fieldAlign:对应类型的结构体的内存对齐大小。
  • kind:类型的枚举值。包含 Go 语言中的所有类型,例如:kindBoolkindIntkindInt8kindInt16 等。
  • equal:用于比较此对象的回调函数。
  • gcdata:存储垃圾收集器的 GC 类型数据。

总结一句,就是类型信息所需的信息都会存储在这里面,其中包含字节大小、类型标志、内存对齐、GC 等相关属性。

runtime.iface

其次就是我们日常在应用程序中应用的较多的 iface,源码如下:

type iface struct {
	tab  *itab
	data unsafe.Pointer
}

我们进一步深入看看 itab 结构体。源码如下:

type itab struct {
	inter *interfacetype
	_type *_type
	hash  uint32 
	_     [4]byte
	fun   [1]uintptr 
}
  • inter:接口的类型信息。
  • _type:具体类型信息
  • hash_type.hash 的副本,用于目标类型和接口变量的类型对比判断。
  • fun:底层数组,存储接口的方法集的具体实现的地址,其包含一组函数指针,实现了接口方法的动态分派,且每次在接口发生变更时都会更新。 与 eface 结构体类型一样,主要也是分为类型和值信息,分别对应 tab 和 data 属性。