这是我参与「第五届青训营 」伴学笔记创作活动的第 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 语言中的所有类型,例如:
kindBool、kindInt、kindInt8、kindInt16等。 - 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属性。