Golang底层原理剖析之method

简介: Golang底层原理剖析之method

方法

如果我们定义一个类型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


目录
打赏
0
1
2
0
9
分享
相关文章
|
10月前
|
Golang底层原理剖析之垃圾回收GC(二)
Golang底层原理剖析之垃圾回收GC(二)
141 0
|
10月前
|
Golang底层原理剖析之上下文Context
Golang底层原理剖析之上下文Context
181 0
GoLang协程Goroutiney原理与GMP模型详解
本文详细介绍了Go语言中的Goroutine及其背后的GMP模型。Goroutine是Go语言中的一种轻量级线程,由Go运行时管理,支持高效的并发编程。文章讲解了Goroutine的创建、调度、上下文切换和栈管理等核心机制,并通过示例代码展示了如何使用Goroutine。GMP模型(Goroutine、Processor、Machine)是Go运行时调度Goroutine的基础,通过合理的调度策略,实现了高并发和高性能的程序执行。
329 29
GoLang协程Goroutiney原理与GMP模型详解
【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
golang 反射基本原理及用法
golang 反射基本原理及用法
54 0
|
10月前
|
Golang深入浅出之-Go语言中的服务网格(Service Mesh)原理与应用
【5月更文挑战第5天】服务网格是处理服务间通信的基础设施层,常由数据平面(代理,如Envoy)和控制平面(管理配置)组成。本文讨论了服务发现、负载均衡和追踪等常见问题及其解决方案,并展示了使用Go语言实现Envoy sidecar配置的例子,强调Go语言在构建服务网格中的优势。服务网格能提升微服务的管理和可观测性,正确应对问题能构建更健壮的分布式系统。
511 1
|
10月前
|
Golang深入浅出之-Go语言中的反射(reflect):原理与实战应用
【5月更文挑战第1天】Go语言的反射允许运行时检查和修改结构,主要通过`reflect`包的`Type`和`Value`实现。然而,滥用反射可能导致代码复杂和性能下降。要安全使用,应注意避免过度使用,始终进行类型检查,并尊重封装。反射的应用包括动态接口实现、JSON序列化和元编程。理解反射原理并谨慎使用是关键,应尽量保持代码静态类型。
120 2
|
10月前
|
Golang底层原理剖析之内存逃逸
Golang底层原理剖析之内存逃逸
64 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等