interface
interface的实现
所有interface,包括有方法和空接口,在内存中都是占据两个字长。那么在32位机器上就是8个字节,在64位机器上就是16个字节。
空interface的底层实现
在Go语言的源码位置: src\runtime\runtime2.go中
type eface struct {
_type *_type //类型指针
data unsafe.Pointer //数据区域指针
}
可以看到对于空的interface,其实就是两个指针。,先看第一个rtype类型, 这个就表示类型基本信息,包括类型的大小,对齐信息,类型的编号
type _type struct {
size uintptr // 类型的大小
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32 // 类型的Hash值
tflag tflag // 类型的Tags
align uint8 // 结构体内对齐
fieldalign uint8 // 结构体作为field时的对齐
kind uint8 // 类型编号 定义于runtime/typekind.go
alg *typeAlg // 类型元方法 存储hash和equal两个操作。map key便使用key的_type.alg.hash(k)获取hash值
gcdata *byte // GC相关信息
str nameOff // 类型名字的偏移
ptrToThis typeOff
}
非空interface的底层实现
type iface struct {
tab *itab
data unsafe.Pointer
}
// 非空接口的类型信息 inter 是接口的定义 而剩下的是实际类型的定义 例如inter 中的method有 set和get两个 那在实例类型中的 fun里也有这两个
type itab struct {
inter *interfacetype // 接口定义的类型信息
_type *_type // 接口实际指向值的类型信息
link *itab
bad int32
inhash int32
fun [1]uintptr // 接口方法实现列表,即函数地址列表,按字典序排序 这里是首地址
}
// 非空接口类型,接口定义,包路径等。
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod // 接口方法声明列表,按字典序排序
}
// 接口的方法声明
type imethod struct {
name nameOff // 方法名
ityp typeOff // 描述方法参数返回值等细节
}
interface有两个重要点
1.赋值 将实际的值转化为interface
1.1 转化为 eface 也就是赋值给空接口 则直接根据 实际值进行内存分配 值拷贝等
1.2 转化为 iface 也就是赋值给有方法的接口 这个时候 会先更具 接口类型和实际类型 获取一个itab,这里会判断实际类型是否实现了接口 ,没有则获取失败。
注:系统会保存一个itab的hash表 通过 接口类型以及实际值的类型可以确定一个itab 也就是获取itab的时候 会先去hash表中找,找不到再生成添加进去 这样做是为了提升性能,不用每次都去判断生成itabl
2.断言 将interface转化为实际的值
判断转化的类型是否有实现接口的方法