golang T 和 *T的方法集是什么关系?
1.结论
-
*T
包含所有T
的方法集,是编译器生成的语法糖(包装方法),实际我们写的非接口类型*T
的场景,编译器会进行“指针解引用”,转而调用T
类型方法。包装方法并不是为了解决我们不同接收者的调用。 -
T
只包含T
的方法集 -
什么是指针解引用?
// pt 是 *T 类型,是指向T的指针 pt.A() // *T类型的方法调用 实际上是下面的方式 (*pt).A() // (*pt)就是指针取值,解引用, 将*pt转成T类型,再调用T的方法 简单来说,就是没有调用*T的包装方法,而是先指针解引用,类型转成T了再调用T的原始方法。所以不是为了方便我们混合类型调用。
2.生成包装方法的原因
- 为了支持接口
interface 的方法,并不能直接“指针解引用”转为具体的类型后调用,因为编译期间并不能确定实现接口的具体类型,没法"指针解引用"
接收者是函数参数的第一个参数,类似python 语言的self
, 分配在栈上,由于编译器不能直接“指针解引用”,就没法知道第一个参数该分配多少空间。那就变相实现咯,给你生成一个一毛一样的,仅仅接收者是 *T
编译器会自动生成同名包装方法,所以语法层面禁止我们给T
和*T
生成同名方法
3.More
- 空接口
```
type eface {
_type *_type // _type叫类型元数据,指向实际被装载(被赋值)的对象的具体类型元数据
data *unsafe.Pointer
}
eface的e是empty的缩写,将一个具体的值obj赋值给一个空接口的时候,其实是将obj的_type 和 地址对应赋值给这两个字段
```
- 非空接口
type iface {
tab *itab // itab是interface table,接口参照表,具体长相看下面
data *unsafe.Pointer
}
type itab struct {
inter *interfacetype //接口自己的类型元数据
_type *_type // 被装载(被赋值)的对象的类型元数据
hash uint32 //类型哈希值
fun [1]uintptr // 方法地址数组,从被赋值的对象的方法元数据那里,拷贝到这里,省得每次都要去具体对象的类型那里去找
}
var i iface
var obj XXX
i = obj // 这一步干了啥呢?下面:
```
1.同上,将`obj地址`赋值给`i.data`; 将`obj的_type`赋值给`i.itab._type`
2.将obj的`方法元数据`数据拷贝到`i.itab.fun`
3.obj的类型哈希 跟 inter类型哈希求亦或,赋值给 hash字段