Go 语言核心 36 讲
郝林
《Go 并发编程实战》作者,前轻松筹大数据负责人
79610 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 55 讲
Go 语言核心 36 讲
15
15
1.0x
00:00/00:00
登录|注册

13 | 结构体及其方法的使用法门

多层嵌入
屏蔽现象
选择表达式
嵌入字段
Go语言的支持
面向对象编程原则
方法集合
接收者声明
方法
字段
值方法与指针方法
Go语言的继承实现
结构体类型的字段声明
结构体类型
知识扩展
结构体类型基础知识
结构体及其方法的使用法门

该思维导图由 AI 生成,仅供参考

我们都知道,结构体类型表示的是实实在在的数据结构。一个结构体类型可以包含若干个字段,每个字段通常都需要有确切的名字和类型。

前导内容:结构体类型基础知识

当然了,结构体类型也可以不包含任何字段,这样并不是没有意义的,因为我们还可以为类型关联上一些方法,这里你可以把方法看做是函数的特殊版本。
函数是独立的程序实体。我们可以声明有名字的函数,也可以声明没名字的函数,还可以把它们当做普通的值传来传去。我们能把具有相同签名的函数抽象成独立的函数类型,以作为一组输入、输出(或者说一类逻辑组件)的代表。
方法却不同,它需要有名字,不能被当作值来看待,最重要的是,它必须隶属于某一个类型。方法所属的类型会通过其声明中的接收者(receiver)声明体现出来。
接收者声明就是在关键字func和方法名称之间的圆括号包裹起来的内容,其中必须包含确切的名称和类型字面量。
接收者的类型其实就是当前方法所属的类型,而接收者的名称,则用于在当前方法中引用它所属的类型的当前值。
我们举个例子来看一下。
// AnimalCategory 代表动物分类学中的基本分类法。
type AnimalCategory struct {
kingdom string // 界。
phylum string // 门。
class string // 纲。
order string // 目。
family string // 科。
genus string // 属。
species string // 种。
}
func (ac AnimalCategory) String() string {
return fmt.Sprintf("%s%s%s%s%s%s%s",
ac.kingdom, ac.phylum, ac.class, ac.order,
ac.family, ac.genus, ac.species)
}
结构体类型AnimalCategory代表了动物的基本分类法,其中有 7 个string类型的字段,分别表示各个等级的分类。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Go语言中的结构体及其方法是本文的主要内容。结构体类型可以包含字段和关联方法,方法是隶属于某一类型的函数。作者通过示例展示了如何为结构体类型编写方法,并介绍了嵌入字段的概念。嵌入字段的方法集合会被无条件地合并进被嵌入类型的方法集合中。文章强调了面向对象编程的原则,并指出Go语言摄取了面向对象编程的优秀特性。通过深入讲解选择表达式、屏蔽现象和多层嵌入的问题,读者可以更好地理解结构体类型及其方法在Go语言中的使用法门。文章内容丰富,涵盖了嵌入字段的各种情况和注意事项,为读者提供了全面的知识体系。 文章重点介绍了结构体类型的嵌入字段、值方法和指针方法的区别,以及Go语言中类型之间的组合方式。强调了嵌入字段是一种实现类型间组合的方式,与继承无关。总结部分提出了两个思考题,引发读者思考和深入探讨。整体而言,本文内容深入浅出,适合Go语言初学者和进阶者阅读,能够帮助他们更好地理解和应用Go语言中的结构体及其方法。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Go 语言核心 36 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(65)

  • 最新
  • 精选
  • 前面都看懂了,最后这里有疑问,老师开始说,值类型的方法由于是类型值的副本,所以不会对原数据修改,指针类型的方法由于是指针的副本,所以会对原数据修改,这里都没有问题,但是,老师又说值类型的方法运行时,会被go自动转译成(&cat).Setname(“newname”),那什么时候值类型会被转译呢

    作者回复: 当值(比如这里说的cat)的方法集合中没有对应方法时,Go会去它的指针的方法集合中寻找,如果找到了,那么Go就会做这种转译。其他情况不会做转译。这属于一种语法糖,让我们能用同一种调用方式调用两种方法(值方法或指针方法)。

    2019-08-13
    2
    22
  • 🐶
    1. 可以嵌入某个类型的指针类型,包括本结构体的指针类型,例如树的结构体的声明。但是在使用之前需要初始化 2. struct{}代表是一个空结构体,不占用内存空间,但是也是一个结构体!

    作者回复: 嗯,对。

    2019-08-11
    2
    20
  • Iflei
    一方面说go支持面向对象,一方面说go没有继承,这不很矛盾吗?面向对象三大特性之一就是继承,没有继承也敢叫面向对象。只是继承实现的方式不同罢了

    作者回复: Go 是把多个编程范式有机地融合在一起了。继承其实是很容易引起程序复杂度飙升的一个东西。GoF 提倡的设计原则中也有“多用组合,少用继承”一条。这不正是 Go 所做的嘛?组合和继承是两个不同的东西,虽然它们在某些时候可以起到同样的作用。 我觉得纯粹的 OO 有利有弊,而且不能说没有完全实现OO 的所有思想就不算支持 OO。

    2019-12-09
    7
    19
  • 杉松壁
    老师,闭包我还是没能理解。 既然是内层的函数需要op的传值,为什么不能直接将op直接传给内层函数,而要通过外层函数的封装?

    作者回复: 内层函数相当于一种函数的不完整定义,外层函数相当于制造这种函数(即完整后的内层函数)的工厂。当你调用外层函数并传入参数值时,相当于在告诉外层函数“根据我给定的参数制造出一个函数”。你想想看,这实际上是在程序的运行过程中动态的生成代码(而不是数据),与创建一个值、一个数据结构的实例是截然不同的。 这里的代码不是死的,而是活的。这也可以被看作是一种简易的元编程。

    2020-06-17
    9
  • 夏云
    这一讲概念性的文字太多,多一些例子就好了,不然第一遍云里雾里的

    作者回复: 可以对照着示例项目中的代码看,实际上我也是这么设计的。另外,这个专栏的定位也不是只讲浅显的东西。一些核心的东西需要大家仔细研习,反复琢磨。想当初我也是这么做的。我希望这些内容能给你们带来长期的好处。 听音频可以让你们有个宏观的了解和大概的感觉,真正学起来还是需要看文字、看代码的。加油!

    2018-09-30
    4
  • 风一般的梦幻
    这句话“同时,类型组合也是非侵入式的,它不会破坏类型的封装或加重类型之间的耦合。”能否和Java对比举例说明一下呢?

    作者回复: 看过设计模式的书吗?其中有一条原则:多用组合,少用继承。这样才能低耦合。另外可以结合“组合模式”思考一下。

    2019-10-30
    3
  • Sky
    函数是独立的程序实体。这一段的表述,有点让人疑惑“函数”和“方法”到底有什么区别?从代码上看,如果没有“接收者类型”,函数和方法是完全一样的。方法如果没有“接收者类型”,那么它就是“函数”,为什么这里说“方法必须隶属于某一个类型”。

    作者回复: 方法的声明形式是:func (xx XX) methodName() {...},其中的 (xx XX) 是接收者声明。这个接收者就是某个类型 XX 啊,xx 是它被实例化后的指代变量。XX 叫接收者类型,xx 叫接收者变量。这就是方法与函数的区别啊。方法必须依附于某个类型,而函数不用,函数是独立的。调用方法的话,只能通过该方法依附的那个类型的某个实例去调用,比如:xx1.methodName()。而函数可以直接调用。 这些在你问的问题里基本都表述出来了。你没有察觉到吗?

    2019-07-01
    3
  • manky
    严格来讲,我们在这样的基本类型的值上只能调用到它的值方法。但是go语言会适时地进行转义.请问什么时候不会出现转义,或者说编译器进行转义有什么必备条件吗?

    作者回复: 在基本值上调用它的指针方法时Go会先对基本值进行取址再调用它的指针方法,这就是我说的转义。

    2018-09-14
    3
  • 咸鱼三月°
    package main import ( "fmt" ) func main() { a := A{} m("A", a, SetAI(&a)) b := B{} m("B", b, SetBI(&b)) } type A struct { I int S string } type B struct { I int } func SetAI(a *A) A { a.I = 10 return *a } func SetBI(b *B) B { b.I = 10 return *b } func m(name string, arg1, arg2 interface{}) { fmt.Println(name+":", arg1, arg2) } 问题:在结构体只有一个属性时 打印方法会打印出相同结果,但是在结构体有多个属性时结果却不相同,上面是测试的代码。感觉很奇怪 输出为什么是 {0 } {10 } 和{10} {10}

    作者回复: 我看到了这个:https://github.com/golang/go/issues/52146 是你提的issue吗? 我试验了一下,有几个方法可以避免这种不一致。比如,编写结构体方法、向 m 函数传递指针,等。 很遗憾,虽然我也觉得这是一个问题,但是Go团队的人貌似并不这么认为。 我现在依然坚持认为这样的不一致是有问题的。不过按照Go团队的说法,只能去用其他方法避免这种情况了。

    2022-04-06
    2
    2
  • HiNeNi
    个人刚从c++转过来,虽然组合很灵活,但是一个对象和哪些interface产生了关联,感觉非常不直观,可读性上不如明确写出继承关系的语言。。。

    作者回复: 这只是习惯问题而已。

    2021-04-14
    2
    2
收起评论
显示
设置
留言
65
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部