news 2026/4/25 18:57:22

Go进阶之理解方法本质

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Go进阶之理解方法本质

Go语言虽然不支持经典的面向对象的语法元素.比如继承 对象和类.Go语言也有方

法.和函数相比就是在声明形式上多了一个参数.Go称为receiver参数.receiver是参

数与类型之间的纽带.

方法声明格式:

func (receiver T/* T) MethodName(参数列表) (返回值列表){ //方法体 }

方法声明的T称为receiver的基类型.通过receiver.上述方法被绑定到类型T上.伪代码如下:

var t T t.methodName(参数列表) var pt *T = &t pt.methodName(参数列表)

    1.Go方法特点:

    1).方法名的首字母是否大写决定了该方法是不是导出方法.

    2).方法定义要与类型定义放在同一个包内.由此可以知道不能为原生类型(如int

    float64 map等)添加方法.只能为自定义类型定义方法.示例如下.

    type MyInt int64 func (i MyInt) String() string { return "自定义类型的方法" }

    同理可以得出不能跨域Go包为其他包内的自定义类型定义方法.

    3).每个方法只能有一个receiver参数.不支持多receiver参数列或变长receiver参

    数.一个方法只能绑定一个基类型.Go语言不支持同时绑定多个类型的方法.

    4).receiver参数的基类型本身不能是指针类型或者接口类型.示例如下.

    2.方法的本质:

    Go语言没有类.方法与类别通过reveiver联系到一起,可以为任何非内置原生类型定

    义方法.示例如下:

    type T struct { a int } func (t T) get() int { return t.a } func (t *T) set(a int) { t.a = a }

    receiver其实是作为第一个参数传入方法列表中.上述的方法可以等价转换为下面的

    函数,代码如下:

    func Get(t T) int { return t.a } func Set(t *T, a int) { t.a = a }

    这种转换后的函数就是方法的原型.只不过在Go语言中.这种等价转换是由Go编译器

    在编译和生成代码时自动完成的.Go语言规范中提供了一个新的概念.可以更充分理解

    等价转换.

    Go方法一般使用方式:

    func Test() { var t T t.get() t.set(1000) }

    等价替换:

    func ChangeTest() { var t T T.get(t) (*T).set(&t, 1000) }

    这种直接以类型名T调用方法的表达式被称为方法表达式.类型T只能调用T的方法集

    合(Method Set)中的方法.同理.*T只能调用*T的方法集合中的方法.这种通过方法表

    达式进行调用的方式与我们之前所做的方法到函数的等价转换如出一辙.这就是Go方

    法的本质.一个方法所绑定类型实例为第一个参数的普通函数.

    Go方法本身就是一个普通函数.我们甚至可以把它作为右值赋值给函数类型的变量.

    func Test() { var t T f1 := (*T).set f2 := T.get f1(&t,1) fmt.Println(f2(t)) }

    3.选择正确的reveiver类型:

    方法和函数的等价变换公式:

    func(t T) M1()<=> M1(t T) func(t *T) M2()<=> M2(t *T)

    M1方法的receiver参数类型为T.M2方法的receiver参数类型为*T.

    1).receiver类型为T时:

    选择以T作为receiver参数类型时.T的M1方法等价于M1(t T).Go函数的参数采用的

    是值复制传递.也就是说M1函数体中的t是T类型的一个副本.这样在M1函数实现中对

    参数t做任何修改都只会影响副本.不会影响到原T类型.

    2).receiver类型为*T时:

    选择以*T作为receiver参数类型时.T的M2方法等价为M2(t *T).我们传递给M2函

    数的t是T类型实例的地址.这样M2函数体中对参数t做的任何修改都会反应到原T类

    型实例上.

    示例如下:

    func main() { //t.a=0 var t T fmt.Println(t.a) t.M1() fmt.Println(t.a) t.M2() fmt.Println(t.a) } type T struct { a int } func (t T) M1() { t.a = 10 } func (t *T) M2() { t.a = 11 }

    执行结果:

    疑惑:是不是T类型实例只能调用receiver为T的类型方法.不能调用receiver为*T类

    型的方法呢.答案是否定.无论T类型实例还是*T类型实例.都既可以调用receiver为T

    类型的方法.也可以调用receiver为*T类型的方法.示例如下:

    func main() { var t T var pt = &T{} t.M1() t.M2() pt.M1() pt.M2() }

    可以看到上述都可以进行互相调用.实际上这都是Go语法糖.Go编译器在编译和生成

    代码时为我们做了自动转换.

    总结:

    如果要对类型实例进行修改.可以为receiver选择*T类型.

    如果没有对类型实例修改的需求.可以为receiver选择T类型或*T类型均可.如果类型

    的size过大的话.选择指针会更好一些.

    微笑着孤言寡语.

    如果大家喜欢我的分享的话.可以关注我的微信公众号

    念何架构之路

    版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
    网站建设 2026/4/18 3:43:04

    跨端前端开发工程师:技术深度、实践与面试指南

    中控技术股份有限公司 前端开发工程师(跨端方向) 职位信息 岗位职责 1、负责公司核心产品的跨端技术架构设计与开发,覆盖Android、iOS、微信/支付宝小程序、H5、Web 网页、鸿蒙(HarmonyOS)等多端场景; 2、主导跨端技术方案选型与落地(如 React Native、Flutter、UniApp、…

    作者头像 李华
    网站建设 2026/4/25 3:14:13

    小额消费贷款产品特征抽取与推荐分析平台的设计与实现开题报告

    一、研究背景与意义 &#xff08;一&#xff09;研究背景 随着数字金融的快速发展与居民消费观念的升级&#xff0c;小额消费贷款已成为满足大众短期资金周转、品质消费需求的重要金融工具。近年来&#xff0c;我国小额消费贷款市场规模持续扩大&#xff0c;参与机构不断增多…

    作者头像 李华
    网站建设 2026/4/18 5:37:59

    YOLO26改进策略【Backbone/主干网络】| CVPR 2024 替换骨干网络为 RMT,增强空间信息的感知能力

    一、本文介绍 本文记录的是将RMT应用于YOLO26骨干网络的改进方法研究。 RMT通过构建基于曼哈顿距离的空间衰减矩阵,引入显式空间先验,同时提出新的注意力分解形式,在不破坏空间衰减矩阵的前提下,以线性复杂度对全局信息进行稀疏建模。将RMT融入YOLO26的骨干网络,能够有效…

    作者头像 李华
    网站建设 2026/4/19 1:33:43

    新零售行业低代码平台应用实践

    在数字化浪潮推动下&#xff0c;新零售行业正经历从“渠道融合”到“全链路智能协同”的转型深水区。线上线下数据割裂、业务流程繁琐、需求迭代滞后、复合型人才短缺等痛点&#xff0c;成为制约企业突破增长瓶颈的核心障碍。低代码平台凭借“可视化搭建、快速迭代、全民参与”…

    作者头像 李华
    网站建设 2026/4/18 11:03:57

    震惊!中国电信AI新神作TeleMem让大模型“开挂“,记忆暴涨38%!小白程序员也能轻松上手!

    思维导图曾被证明可以帮助学习障碍者快速提升成绩&#xff0c;那么当前已经可堪一用的智能体系统如果引入类似工具是否可以帮助改善长期学习记忆能力呢&#xff1f;有研究团队做出了探索性尝试。 在长上下文和Agent应用不断落地的过程中&#xff0c;越来越多研究者开始意识到&…

    作者头像 李华