GoLang之T和*T的方法集

GoLang之T和*T的方法集

1.深究

1.1两大问题

基于我们之前介绍过的类型元数据相关知识,T和*T是两种类型,分别有着自己的类型元数据,一些元数据相关知识t he兴替是两种类型,分别有着自己的类型元数据,而根据自定义类型的类型元数据可以找得到该类型关联的方法列表。

在这里插入图片描述

既然T和T各有各的方法集,那为什么还要限制T和T不能定义同名方法,

在这里插入图片描述

又怎么会有"*T的方法集包含T的方法集合“这种说法?

在这里插入图片描述

1.2T的方法集:接收者为T类型的方法

接下来咱们就来梳理下这两个问题。

首先可以确定的是,T的方法集里全部都是有明确定义的接收者为T类型的方法,

在这里插入图片描述

1.3*T的方法集:接收者为*T类型的方法+包装方法

T的方法集里除了有明确定义的接收者为T的方法以外,还会有编译器生成的一些”包装方法“,这些包装方法是对接收者为T类型的同名方法的“包装”,

在这里插入图片描述

1.4包装方法语法糖

为什么编辑器要为接受者为T的方法包装一个接收者为*T的同名方法呢?

在这里插入图片描述

这里首先要明确一点,“通过*T类型的变量直接调用T类型接收者的方法”只是一种语法糖,经验证:这种调用方式,编译器会在调入端进行指针解引用,并不会用到这里的包装方法。

在这里插入图片描述

1.5解释两大问题

实际上编译器生成包装方法主要是为了支持接口,还记得接口的数据结构吗?。涉及到方法,自然是非空接口。它只包含两个指针,一个和类型元数据相关,一个和接口装载的数据相关。

在这里插入图片描述

虽然有数据指针,但却不能像这里的语法糖那样通过指针解引用来调用值接收者的方法。
至于原因嘛,你想,方法的接收者是方法调用时隐含的第一个参数,go语言中函数参数是通过栈来传递的,如果参数是指针类型,那就很好实现,平台确定了,指针大小就确定了。但如果要解引用为值类型,就要有明确的类型信息,编译器才能确定这个参数要在栈上占用多大的空间。
而对于接口,编译阶段并不能确定他会装载哪一类数据,所以编译器也不能生成对应的指令来解引用
总而言之,接口不能直接使用接收者为值类型的方法。

在这里插入图片描述

面对这个问题,编译器选择为值接收者的方法生成指针接收者的同名包装方法这一解决方案。也正因为如此,如果我们再给T和T定义同名方法,就有可能和编译器生成的包装方法发生冲突,所以go语言干脆不允许为T和T定义同名方法。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.6分析可执行文件

至于说"T的方法集"及包含"T的方法集的所有方法"。这种说法可以这样理解。虽然编译器会对所有接收者为T的方法生成接收者为T的包装方法,但是链接器会把程序中确定不会用到的方法都裁剪掉

在这里插入图片描述

所以,如果去分析可执行文件的话,就会发现,不只是这些包装方法,就连我们明确定义的方法也不一定会存在于可执行文件中。不过一定要记得从可执行文件去分析,不能通过反射在程序中验证,因为反射的实现也是基于接口,通过反射来验证,会被链接器认为用到了这个方法,从而把它保留下来,这就测不准了。

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值