非空interface - iface
type iface struct {
tab *itab
data unsafe.Pointer
}
非空interface的底层结构是iface。iface结构中,存在两个字段,*itab类型的tab字段,unsafe.Pointer类型的data字段。
tab *itab
tab字段描述的是此interface代表的变量的类型,拥有的方法这些信息。itab结构体描述了这些信息
type itab struct {
inter *interfacetype
_type *_type
hash uint32
_ [4]byte
fun [1]uintptr
}
接下来展开介绍其中的字段。
inter *interfacetype
inter字段存放的是interface自己的静态类型。即代表interface这个类型
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
如代码所示,interfacetype结构体中,字段typ既是代表interface这个类型,因为_type类型的数据其实就是指的是go里的类型数据;pkgpath字段代表的是这个interface所在的pkg的路径。mhdr代表的是这个interface里拥有的方法的List。看imethod结构的代码,可以得知,interfacetype结构中存储方法,实际上是存储的是方法在最终段内的偏移量,知道偏移量后才能方便调用
type imethod struct {
name nameOff
ityp typeOff
}
nameOff和typeOff两种类型,在下面会介绍到
_type *_type
type字段存储的是interface代表的数据的类型。详细看看_type的结构。 _type可以说就是所有类型最原始的元信息
type _type struct {
size uintptr // 类型占用内存大小
ptrdata uintptr // 包含所有指针的内存前缀大小
hash uint32 // 类型hash
tflag tflag // 标记位,主要用于反射
align uint8 // 对齐字节信息
fieldAlign uint8 // 当前结构字段的对齐字节数
kind uint8 // 基础类型枚举值
// function for comparing objects of this type
// (ptr to object A, ptr to object B) -> ==?
equal func(unsafe.Pointer, unsafe.Pointer) bool // 比较两个形参指向的对象类型是否相等
// 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 // GC类型数据
str nameOff // 类型名称字符串在二进制文件段中的偏移量
ptrToThis typeOff // 类型元信息指针在二进制文件段中的偏移量
}
结构体中str和ptrToThis对应的类型是nameOff和typeOff,是由链接器在段合并和符号重定向的时候赋值的。
链接器将各个 .o 文件中的段合并到输出文件,会进行段合并,有的放入 .text 段,有的放入 .data 段,有的放入 .bss 段。name 和 type 针对最终输出文件所在段内的偏移量 offset 是由 resolveNameOff 和 resolveTypeOff 函数计算出来的,然后链接器把结果保存在 str 和 ptrToThis 中。
func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {}
func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {}
hash uint32
itab结构体中的hash字段,其实就是 _type 类型内的hash字段
fun [1]uintptr
fun字段,存放的是该interface代表的数据所拥有的具体的方法的函数指针。这里虽然长度为1,但可以通过指针便宜,找到后面依次排列的其他方法。同时,如果fun[0] == 0,就代表 _type 这个类型没有实现这个interface.
data unsafe.Pointer
iface结构的的data字段,指向了这个interface代表的具体数据。
空interface - eface
type eface struct {
_type *_type
data unsafe.Pointer
}
Go语言底层对非空interface和空interface实现上做了区分。空interface的底层结构是eface结构。它与iface的区别在于,它拥有的不再是 *itab类型数据,而是 _type 类型的数据。是因为,eface面向的是空的interface数据,既然是空的interface,那么只需要用 *_type 代表类型,data字段指向具体数据即可。这里的 *_type 是此interface代表的数据的类型。
总的来说
只有 interfacetype类型的数据,才代表的interface自身的类型和数据。其他情况下使用 _type 都是代表了interface代表的那个具体数据的类型。