Golang底层原理剖析之method

本文深入探讨Go语言中方法与函数的关系,指出方法实际上是带有接收者的普通函数。值接收者与指针接收者在方法调用时的区别在于参数拷贝和修改对象的不同。同时,介绍了方法表达式和方法变量的概念,方法表达式等价于函数值,而方法变量可能形成闭包。文章还通过实例解析了如何通过值或指针调用不同接收者类型的方法,并讨论了方法变量作为返回值时闭包的形成情况。
摘要由CSDN通过智能技术生成

方法

在这里插入图片描述
如果我们定义一个类型A,并给它关联一个方法,然后就可以通过这个类型A的变量来调用这个方法了,这种调用方式其实是“语法糖”实际上和下面这种方式是一样的。这里变量a就是所谓的方法接收者,它会作为方法Name的第一个参数传入。这一点我们可以通过右边的代码验证一下,Go中函数类型只和参数与返回值相关,所以这两个类型值相等就能够证明方法本质上就是普通的函数。而接收者就是隐含的第一个参数。

在这里插入图片描述
下面来看看方法调用的情况,man函数栈帧局部如图,传参值拷贝,函数内a.name指向新的字符串内容,这里的局部变量a是值接收者,通过它调用方法时,修改的是拷贝过去的参数。而不是局部变量a,要想修改局部变量a,要用指针接收者。
在这里插入图片描述
把上面方法Name的接收者改为指针类型,然后用pa来调用方法Name。pa.Name()会被转换成(*A).Name(pa)这样的函数调用。传参值拷贝,这里拷贝的是局部变量a的地址,修改的是局部变量a。这就是指针接收者调用方法的过程,同样要把接收者作为第一个参数传入。同样是参数值拷贝,但是指针接收者拷贝的是地址,因此实现了对局部变量a的修改。

在这里插入图片描述

这里既有值接收者的方法,又有指针接收者的方法,我们已经了解了两种接收者调用方法的基本过程,但是main函数中通过值调用指针接收者的方法,通过指针调用值接收者的方法。也能正常运行是什么意思??其实若没有涉及到接口的话,这些也是语法糖,编译阶段它会转换成这种形式。不过既然这种语法糖在编译期间发挥作用的,像编译期间不能拿到地址的字面量是不能借助语法糖来转换的,因此并不能通过编译。

方法表达式 & 方法变量

在这里插入图片描述

总结

最后来看一下把一个方法赋给一个变量是怎么回事,我们已经知道Go中函数作为变量,参数和返回值时,都是以Function Value的形式存在的,也知道闭包只是有捕获列表的Function Value而已。如果把一个类型的方法赋给变量f1,f1就是一个方法表达式。这实际上等价于f1:=GetName,所以f1本质上也是一个function value,也就是一个funcval结构体的指针,fn指向A.Getname的函数指令入口。 因为前面我们已经验证了这两个方法的等价性,所以通过f1执行方法时,需要传入A类型的变量a作为第一个参数,而f2:=a.GetName以这样的方式赋值,它被称为方法变量,理论上讲,方法变量也是一个FunctionValue,而且它会捕获方法接收者, 形成闭包,但是这里f2仅作为局部变量,它与a的生命周期是一致的,所以编译器会做出优化,把它转换成类型A的方法调用并传入a作为参数。

在这里插入图片描述

我们可以看一个方法变量作为返回值的例子,对比一下。这里f2与上个例子相同,它会被编译器做出优化,而下面的f3赋值为GetFunc函数的返回值,返回的是一个方法变量,这等价于这样一段代码。通过这一段代码我们可以清晰的看到闭包是如何形成的,所以这里的f3就是一个闭包对象,捕获了GetFunc函数的局部变量a。

在这里插入图片描述
因此从本质上来讲,方法表达式和方法变量都是function value

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cheems~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值