《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语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...
随机推荐
- NEMU PA 2-1 实验报告
课程地址:https://www.bilibili.com/video/BV1TE411P7tq 一.实验目的 通过PA2-0了解了汇编基础知识和如何去阅读i386手册后,在这个阶段我们就需要: 了解 ...
- centos7使用repo方式安装zabbix4.0
1.安装zabbix的repo源 rpm -ivh https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/4.0/rhel/7/x86_64/zabbi ...
- C++ 析构函数的调用顺序
如果指针指向基类,但是指针在运行时指向派生类,则该基类必须具有虚拟析构函数,以便破坏派生类.如果没有虚拟析构函数,则只会运行基类的析构函数. 比如: Base* basePtr; basePtr = ...
- 公司服务器建站笔记(三):腾讯云服务器CentOS8.2安装界面环境,使用vnc远程登陆并搭建轻量级Qt服务器
前言 有些小项目可能只有几个点,几十个点,几百个点,这个时候使用qt的tcp服务器或者mqtt或者websocket等相关服务就可以满足,腾讯云CentOs8.2服务器安装的是没有界面的版本,本篇 ...
- 产品分享:Qt数学函数公式学科工具,当前版本v1.0.0
若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/121194536红胖子(红模仿)的博文大全:开发技术集合 ...
- Celery在Django项目中集成
使用celery第一件要做的最为重要的事情是需要先创建一个Celery实例对象,我们一般叫做celery应用对象,或者更简单直接叫做一个app.app应用对象是我们使用celery所有功能的入口,比如 ...
- python代码,读取一个txt文件,将其中的每一行开头加上一个字母a,每一行的结尾加上一个字母b
with open('name.txt', 'r+') as file: lines = file.readlines() file.seek(0) # 将文件指针移回文件开头 file.trunca ...
- 连接微信群、Slack 和 GitHub:社区开放沟通的基础设施搭建
NebulaGraph 社区如何构建工具让 Slack.WeChat 中宝贵的群聊讨论同步到公共领域. 要开放,不要封闭 在开源社区中,开放的一个重要意义是社区内的沟通.讨论应该是透明.包容并且方便所 ...
- 开源:Taurus.Idempotent 分布式幂等性锁框架,支持 .Net 和 .Net Core 双系列版本
分布式幂等性锁介绍: 分布式幂等性框架的作用是确保在分布式系统中的操作具有幂等性,即无论操作被重复执行多少次,最终的结果都是一致的.幂等性是指对同一操作的多次执行所产生的效果与仅执行一次的效果相同. ...
- Codeforces Round 260 (Div. 1)A. Boredom(dp)
最开始写了一发贪心wa了,然后这种选和不选的组合优化问题,一般是考虑动态规划 \(dp[i][0]:\)表示第i个数不选的最大值 \(dp[i][1]:\)表示第i个数选的最大值 考虑转移: \(dp ...