首页 > 其他分享 >Go语言精进之路读书笔记第23条——理解方法的本质以选择正确的receiver类型

Go语言精进之路读书笔记第23条——理解方法的本质以选择正确的receiver类型

时间:2024-02-13 11:55:47浏览次数:32  
标签:23 int 读书笔记 类型 func receiver Go 方法

和函数相比,Go语言中的方法在声明形式上仅仅多了一个参数,Go称之为receiver参数。receiver参数是方法与类型之间的纽带。

Go方法特点:

  • 方法名的首字母是否大写决定了该方法是不是导出方法。
  • 方法定义要与类型定义放在同一个包内。由此可以推出,不能为原生类型(如int/float64/map等)添加方法,只能为自定义类型定义方法。不能横跨Go包为其他包内的自定义类型定义方法。
  • 每个方法只能有一个receiver参数,不支持多receiver参数列表,不支持变长receiver参数,不支持同时绑定多个类型。
  • receiver参数的基类型本身不能是指针类型或接口类型

23.1 方法的本质

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

// 等价转换,将receiver作为第一个参数传入方法的参数列表,转换之后就是方法的原型
func Get(t T) int {
    return t.a
}
func Set(t *T, a int) int {
    t.a = a
    return t.a
}
// 使用方法
var t T
t.Get()
t.Set(1)
// 等价替换为
var t T
T.Get(t)
(*T).Set(&t, 1)

直接以类型名T调用方法的表达方式被称为方法表达式(Method Expression)

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

23.2 选择正确的receiver类型

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

Go函数的参数采用的是值复制传递,M1函数体中的t是T类型实例的一个副本,M2函数体中的t是T类型实例的地址

无论是T类型实例还是*T类型实例,都可以调用receiver为T类型或*T类型的方法。实际上是Go语法糖,Go编译器在编译和生成代码时为我们做了自动转换

初步结论:

  • 如果要对类型实例进行修改,使用*T类型
  • 如果没有修改的需求,使用T类型和*T类型均可。如果考虑Go方法调用时,receiver是以值复制的形式传入方法中的,选择*T类型会减少损耗

23.3 基于对Go方法本质的理解巧解难题

  • data1输出:one two tree
    • 迭代data1时,由于data1中的元素类型是field指针(*field),因此赋值后v就是元素地址,每次调用print时传入的参数(v)实际上也是各个field元素的地址
  • data2输出:six six six
    • 迭代data2时,由于data2中的元素类型是field(非指针),需要将其取地址后再传入,这样每次调用print时传入的参数(&v)实际上是变量v的地址,而不是切片data2中各元素的地址
    • 在整个for range过程中v只有一个,因此data2迭代完成之后,v是元素“six”的副本
type field1 struct {
    name string
}

func (p *field1) print() {
    fmt.Println(p.name)
}

func main() {
    data1 := []*field1{{"one"}, {"two"}, {"three"}}
    for _, v := range data1 {
        go v.print()
    }

    data2 := []field1{{"four"}, {"five"}, {"six"}}
    for _, v := range data2 {
        go v.print()
    }

    time.Sleep(3 * time.Second)
}

标签:23,int,读书笔记,类型,func,receiver,Go,方法
From: https://www.cnblogs.com/brynchen/p/18014460

相关文章

  • Go语言精进之路读书笔记第22条——使用defer让函数更简介、更健壮
    22.1defer的运行机制在Go中,只有在函数和方法内部才能使用defer。defer关键字后面只能接函数或方法,这些函数被成为deferred函数。defer将它们注册到其所在goroutine用于存放deferred函数的栈数据结构中。在执行defer的函数退出前,按后进先出(LIFO)的顺序调度执行。22.2defer的......
  • Go语言精进之路读书笔记第21条——让自己习惯于函数是"一等公民"
    21.1什么是"一等公民"(1)正常创建//$GOROOT/src/fmt/print.gofuncnewPrinter()*pp{p:=ppFree.Get().(*pp)p.panicking=falsep.erroring=falsep.wrapErrs=falsep.fmt.init(&p.buf)returnp}(2)在函数内创建,定义匿名函数赋值给......
  • Go语言精进之路读书笔记第20条——在init函数中检查包级变量的初始状态
    20.1认识init函数init函数的特点:运行时调用,Go程序中不能显式调用顺序执行,等待一个init函数执行完毕并返回后再执行下一个init函数在整个Go程序生命周期内仅会被执行一次先被传递给Go编译器的源文件中的init函数先被执行,同一个源文件中的多个init函数按声明顺序依次执行。但......
  • GDKOI2023 错排
    逆天。转化后的题意\(q\)组询问,求有\(n-m\)个自由元素,\(m\)个限制元素的错排问题。\(1\len,m,q\le2\times10^5\)首先写出两种组合意义的转移方程:\[\begin{aligned}f(n,m)&=f(n,m-1)-f(n-1,m-1)\\f(n,m)&=(m-1)f(n-1,m-2)+(n-m)f(n-1,m-1)\end{aligned}\]......
  • 623 在二叉树中增加一行
    深度遍历,就是遍历:1.先要确定有几种情况,像这道题,深度为1,2就是最基本的情况,分为两种处理;2.根据不同情况,进行不同处理,不需要考虑后面递归的传递。3.确认传递的方式,如果函数返回的是指针,就需要left,right接住。完整代码:点击查看代码classSolution{public:TreeNode*ad......
  • 【学习笔记】李宏毅 2023 春机器学习课程听课记录
    1ChatGPT原理剖析ChatGPT的社会化:学会文字接龙人类引导文字接龙方向模仿人类喜好用增强式学习向模拟老师学习1.1预训练(Pre-train)ChatGPT真正在做的事情本质上是文字接龙,将其看成一个函数\(f(x)\),其中的\(x\)自变量可以是用户输入的一个语句,得到的函数就是接下来......
  • 一月读书笔记《程序员修炼之道:从小工到专家》
    首先,书中对个人责任和职业发展观念的深刻阐述,让我深受触动。我意识到,作为一名程序员,我们所承担的不仅仅是一份工作,更是一份沉甸甸的责任。每一行代码、每一个程序都是我们用心创造的作品,它们不仅仅是为了完成任务而存在,更是在无形中推动着社会的进步。我们的工作成果可能会影响到......
  • 一月读书笔记《人月神话》
    《人月神话》读后感作为一名学生,我对软件工程领域一直充满好奇和热情。在这个信息技术迅猛发展的时代,软件已经渗透到我们生活的方方面面。《人月神话》是软件工程领域的经典之作,由经验丰富的软件项目经理FrederickP.Brooks,Jr.所著。作者以自己在IBM公司担任大型软件项目经理......
  • 一月读书笔记《梦断代码》
    《梦断代码》主要围绕OSAF主持的Chandler项目进行展开,深入剖析了软件开发过程中的种种问题和挑战。通过作者的详细叙述,我仿佛置身于项目的开发现场,亲身经历了那些充满波折和挫折的时刻。首先,书中对软件开发复杂性的描述让我深感震撼。在Chandler项目的开发过程中,作者展示了各种技......
  • V的2023 - 虽迟但到
    一年一度的年终总结又来了,只感叹时光飞逝,这几年的年终总结对我来说就好像是一年写一次的日记,记忆会模糊,但文字不会。这是第四年,每次回首前几年的文章,心中都会有一丝触动,原来生活给我留下过深刻痕迹。V的2022-往事随风不平凡的2021年ykCoder的2020年年终总结爬山散心二......