《Go程序设计语言》学习笔记之结构体
《Go程序设计语言》学习笔记之结构体
一. 环境
Centos8.5, go1.17.5 linux/amd64
二. 概念
结构体是将零个或者多个任意类型的命名变量组合在一起的聚合数据类型。每个变量都叫做结构体的成员。
三. 声明/初始化
1) 定义一个结构体类型 Human,然后通过它定义一个命名结构体变量 child。
8 type Human struct {
9 Name string
10 Age int
11 Height float64
12 }
13
14 var child Human
15
16 func main() {
17 child.Name = "Jim"
18 child.Height = 90.0
19 child.Age = 4
20
21 fmt.Printf("%#v\n", child)
22 }
运行结果如下

结构体的成员变量通常一行写一个,变量的名称在类型的前面,但是相同类型的连续成员变量可以写在同一行上。
成员变量的顺序对于结构体同一性很重要,如果我们调整了成员的顺序,那么我们就在定义一个不同的结构体类型。
如果一个结构体的成员变量名称是首字母大写的,那么这个变量是可导出的,这个是Go最主要的访问控制机制。一个结构体可以同时包含可导出和不可导出的成员变量。
命名结构体类型 S 中,不可以定义一个拥有相同结构体类型 S 的成员变量,也就是一个聚合类型不可以包含它自己。否则,编译会报错,提示“无效的递归类型”,如下

但是,结构体类型 S 中 可以定义一个 S 的指针类型,即 *S ,这样可以创建一些递归数据结构如链表、树。
2) 零值
结构体的零值由结构体成员的零值组成。通常情况下,零值是一个默认的自然的、合理的值。
26 type Test struct {
27 Size int
28 Buffer string
29 IsBool bool
30 Mut sync.Mutex
31 }
32
33 func main() {
34 t1 := Test{}
35 fmt.Printf("%#v\n", t1)
36 }
运行结果如下

结构体类型 Test 前面三个成员的零值,整型的零值为 0,字符串类型的成员零值为空字符串, 布尔类型的成员零值为 false,sync.Mutex类型的成员是一个可以直接使用且未锁定状态的互斥锁。
3) 通过结构体字面量来初始化结构体变量
一种方式是按照正确的顺序,为每个成员变量指定一个值,如 p1。这种方式适用于小型的大家都比较容易理解的结构体,比如 Point 类型结构体。
另一种方式是通过指定部分或全部成员变量的名称和值来初始化结构体变量,如 p2。这种方式一般用的较多。
8 type Point struct {
9 X float64
10 Y float64
11 }
12
13 func main() {
14 p1 := Point{3.0, 4.0}
15 p2 := Point{X: 2.0, Y: 5.0}
16
17 fmt.Printf("%v\n", p1)
18 fmt.Printf("%v\n", p2)
19 }
初始化一个结构体变量的指针
20 pp := &Point{5, 8}
21 fmt.Printf("%v\n", *pp)
这个等价于
23 pp2 := new(Point)
24 *pp2 = Point{5, 8}
25 fmt.Printf("%v\n", *pp2)
&Point{5, 8} 这种方式可以直接使用在一个表达式中,例如函数调用。
四. 访问
结构体的每个成员都可以通过点号方式来访问,也可以获取成员变量的地址,然后通过指针来访问它。
h1 通过点号来访问成员 Age,h1 通过指针修改了成员变量 Height 的值。
19 func main() {
20 h1 := Human{"Jim", 21, 65}
21
22 h1.Age++
23 *(&h1.Height) += 2.0
24 fmt.Printf("%#v\n", h1)
25 }
运行结果如下

五. 比较
如果结构体的所有成员变量都可以比较,那么这个结构体就是可比较的。两个结构体的比较可以使用 == 或者 !=。== 操作符按照顺序比较两个结构体变量的成员变量。
第28和第29两行代码的语句是等价的
26 p1 := Point{1, 2}
27 p2 := Point{2, 1}
28 fmt.Printf("%t\n", p1.X == p2.X && p1.Y == p2.Y)
29 fmt.Printf("%t\n", p1 == p2)
可比较的类型都可以做为 map 的键类型,结构体变量 addr 作为 map 变量 acce 的键值
19 type address struct {
20 Ip string
21 Port string
22 }
23
24 func main() {
25 addr := address{"127.0.0.1", "9090"}
26 acce := make(map[address]int)
27 acce[addr]++
28 fmt.Printf("%v\n", acce)
29 }
运行结果如下

六. 使用
1) 作函数参数
一般使用指针传递的方式,一是出于效率的考虑,二 是当需要结构体变量时这种方式就是必需的。
值传递,调用者接收到的实参的一个副本,并不是实参的引用。
2) 结构体嵌套和匿名成员
a. 结构体嵌套,这个机制可以让我们将一个命名结构体当作另一个结构体类型的匿名成员使用,并提供了方便的访问方式。
借用书上的例子,下面示例代码,结构体中嵌套了命名结构体,访问结构体变量 w 中的成员时,使用到了中间的结构体变量。
8 type Point struct {
9 X int
10 Y int
11 }
12
13 type Circle struct {
14 Center Point
15 Radius int
16 }
17
18 type Wheel struct {
19 Circle Circle
20 Spokes int
21 }
22
23 func main() {
24 var w Wheel
25 w.Circle.Center.X = 2
26 w.Circle.Center.Y = 3
27 w.Circle.Radius = 5
28 w.Spokes = 10
29 fmt.Printf("%#v\n", w)
30 }
在 Go 中,可以定义不带名称的结构体成员,只需要指定类型即可;这种结构体成员称作匿名成员。这个结构体成员必须是一个命名类型或者一个指向命名类型的指针。
8 type Point struct {
9 X int
10 Y int
11 }
12
13 type Circle struct {
14 Point
15 Radius int
16 }
17
18 type Wheel struct {
19 Circle
20 Spokes int
21 }
22
23 func main() {
24 var ww Wheel
25 ww.X = 2
26 ww.Y = 3
27 ww.Radius = 5
28 ww.Spokes = 10
29 fmt.Printf("%#v\n", ww)
30
31 var w Wheel
32 w.Circle.Point.X = 2
33 w.Circle.Point.Y = 3
34 w.Circle.Radius = 5
35 w.Spokes = 10
36 fmt.Printf("%#v\n", w)
37
38 }
Circle 中有一个匿名成员 Point,Wheel 中有一个匿名成员 Circle。结构体变量 ww 可直接访问到需要的成员变量,而不需要指定一大串中间变量。结构体变量 w 的访问成员的方式也是正确,可以看到这种方式相对繁琐了不少。
运行结果如下

b. 嵌套结构体的初始化
与前面一致。一种是按照顺序初始化,另一种是使用成员变量的名称与值进行初始化。
23 func main() {
24 w := Wheel{Circle{Point{3, 4}, 5}, 10}
25 fmt.Printf("%v\n", w)
26
27 ww := Wheel{
28 Circle: Circle{
29 Point: Point{
30 X: 3,
31 Y: 4,
32 },
33 Radius: 5,
34 },
35 Spokes: 10,
36 }
37 fmt.Printf("%v\n", ww)
38 }
两种方式打印结果一致

第31行,33行,35行最后面的逗号都需要带上,不然会编译报错。
c. 匿名成员不一定是结构体类型,任何命名类型或者指向命名类型的指针都可以。
结构体类型 MyType 中的成员 Ages 和 Weight 都是自定义的类型,Name 是内置类型,ContactInfo 是嵌套的结构体类型。
23 type Ages int
24 type Weight float64
25
26 type ContactInfo struct {
27 Addr string
28 PhoneNum string
29 }
30
31 type MyType struct {
32 Name string
33 Ages
34 Weight
35 ContactInfo
36 }
37
38 func main() {
39 var t1 MyType
40 t1.Ages = 20
41 t1.Weight = 55
42 t1.Name = "Bob"
43 t1.Addr = "BeiJing"
44 t1.PhoneNum = "18888888888"
45 fmt.Printf("%v\n", t1)
46 }
打印结果如下

以快捷方式访问匿名成员的内部变量同样适用于访问匿名成员的内部方法。因此,外围的结构体类型获取的不仅仅是匿名成员的内部变量,还有相关的方法。
《Go程序设计语言》学习笔记之结构体的更多相关文章
- c语言学习笔记之结构体存储
今天讲讲结构体存储问题 首先,结构体简单说是对不同类型的封装,一开始我们可能会想结构体在内存中的存储的大小是直接元素的和 例如 我们可能会觉得是 结构体大小=int(4个字节)+ short(2个字节 ...
- C语言学习笔记--枚举&结构体
枚举 枚举是一种用户定义的数据类型,它用关键字enum以如下语法格式来声明: enum 枚举类型名字 {名字0,名字1,...,名字n}: 枚举类型名字通常并不真的使用,要用的是大括号里面的名字,因为 ...
- C语言学习笔记10-结构体、枚举、联合体
C语言学习笔记10-结构体.枚举.联合体 待传
- contiki学习笔记---process结构体
process,字面意义,进程,看看它的结构 struct process { struct process *next; #if PROCESS_CONF_NO_PROCESS_NAMES #def ...
- C#学习笔记之结构体
1.概述 结构是一种与类相似的数据类型,不过它较类更为轻量,一般适用于表示类似Point.Rectangle.Color的对象.基本上结构能办到的类全都能办到,但在某些情况下使用结构更为合适,后面会有 ...
- 《PHP7底层设计与源码实现》学习笔记2——结构体对齐
书里给了一段代码,假如有个结构体如下: struct test { char a; int b; long c; void* d; int e; cha ...
- C程序设计语言学习笔记
在Windows下运行C语言程序 Windows下的编程工具使用 VC 6.0,下面讲解如何在VC 6.0下运行上节的"Hello, world"程序. 1) 新建Win32 Co ...
- 【C#学习笔记】结构体使用
using System; namespace ConsoleApplication { struct _st { public string name; public int age; } clas ...
- Go语言学习笔记十: 结构体
Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...
- 2017-05-4-C语言学习笔记
C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...
随机推荐
- NC22593 签到题
题目链接 题目 题目描述 恭喜你找到了本场比赛的签到题! 为了让大家都有抽奖的机会,只需要复制粘贴以下代码(并且稍微填下空)即可 AC: (我超良心的) #include <algorithm& ...
- 将CH340G的USB2TTL扩展出RTS, DTR口
关于 要测试串口中的RTS和DTR, 最常见的USB2TTL基于CH340G, 并没有引出RTS, 然而这个IC是支持这些信号的, 只是PCB上将这些pin留空了. 这块板子的PCB 电路 详细信息可 ...
- 【Unity3D】人物跟随鼠标位置
1 游戏对象 2D动画和人体模型及动画中介绍了 Aniamtion.Animator.人体模型.人体骨骼.人体动画等基础知识,本文将通过 "人物跟随鼠标位置" 案例加强对 Un ...
- 【Unity3D】UGUI之Text
1 Text 简介 UGUI概述 中介绍了Canvas 渲染模式.RectTransform 组件.锚点(Anchor)等,本文将介绍 UGUI 中的 Text 控件. 在 Hierarchy ...
- 链表--insert
分别是使用了二级指针和一级指针的两种方法,最后会按插入的顺序依次打印1,2,3,4 主要区别在于,使用二级指针,可以在main函数里直接用一个空的Node指针,而一级指针是在main函数里面先添加了一 ...
- Ansible原理和安装
目录 Ansible Ansible简介 Ansible的特性 Ansible的基本组件 Ansible安装(rhel8/rhel9) 1. rhel8安装 1.1 配置epel源 1.2 安装ans ...
- 【Android 逆向】frida 检测绕过
1. aaa.apk 安装到手机,是一个叫玩吧的应用 ./hooker ...... 23248 浏 览 器 com.browser2345_oem 32541 玩吧 com.wodi.who 244 ...
- [BUUCTF][WEB][极客大挑战 2019]Upload 1
打开靶机url,看到一个页面可以上传文件 上传一个图片试一下,发现上传的路径是 http://a7661b03-4852-41de-9ea4-d48c47cb50f0.node4.buuoj.cn:8 ...
- python如何多版本共存
1. 先正常安装多个python版本,比如我电脑里面是安装的3.10以及3.12 2. 安装的时候建议不要选择系统盘,可以用两个目录安装,例如: d:\py310\... d:\py312\... 3 ...
- 第135篇:Three.js基础入门
好家伙,这东西太帅了,我要学会 先放张帅图(都是用three.js做出来的,这我学习动力直接拉满) 还有另外一个 Junni is... 帧数太高,录不了 开始学习 官方文档 1.Thr ...