《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语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...
随机推荐
- NC24605 [USACO 2011 Ope S]Corn Maze
题目链接 题目 题目描述 This past fall, Farmer John took the cows to visit a corn maze. But this wasn't just an ...
- Java 根据Map的值对 List<Map<String, Object>> 进行排序
对 List<Map<String, Object>> 类型数据的排序 有一个Map列表, 需要对这个列表, 按Map的某几个value进行排序, 并且还要分别指定正序或者倒序 ...
- 一个Git Commit Message模板
一个统一的commit消息模板可以约束团队成员使用一致的方式提交变更信息,这样也方便集成工具进行合规检查. 通常来讲,commit信息应该包含如下内容: <type>(<scope& ...
- java+mysql数据库实现的学生管理系统
说明: java+mysql数据库实现的学生管理系统 功能 实现增加学生.删除学生.修改学生.学生列表.查询学生功能 截图: 开发工具/技术 java eclipse 价格:50元,有需要联系 微信 ...
- 【LeetCode回溯算法#11】解数独,这次是真的用回溯法处理二维数组
解数独 力扣题目链接(opens new window) 编写一个程序,通过填充空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次. 数字 1-9 在每一列只能出 ...
- OpenCV计数应用 c++(QT)
一.前言 为了挑战一下OpenCV的学习成果,最经一直在找各类项目进行实践.机缘巧合之下,得到了以下的需求: 要求从以下图片中找出所有的近似矩形的点并计数,重叠点需要拆分单独计数. 二.解题思路 1. ...
- 【Azure Redis 缓存】使用Azure Redis服务时候,如突然遇见异常,遇见命令Timeout performing SET xxxxxx等情况,如何第一时间查看是否有Failover存在呢?
问题描述 使用Azure Redis服务时,如突然遇见异常,命令Timeout performing SET xxxxxx等情况,如何第一时间查看是否有Failover存在呢?看是否有进行平台的维护呢 ...
- C笔记(2014-12备份)
Video1: 1-编译器对待全局变量和局部变量的差别.全局变量分配空间是在数据区,局部变量分配在代码区. (比如局部变量 int lo_var = 2;后面的 = 2;是赋值语句,被编译器转化成机器 ...
- SpringCloud Ribbon和Feign 的使用和源码分析
1. Ribbon 介绍 Ribbon 是 Netflix 公司开源的一款 客户端 负载均衡软件,并被SpringCloud集成 作为SpringCloud 负载均衡的工具 服务端负载均衡 : 即在服 ...
- SQL之 数据库表字段约束与索引
第三范式 MySQL四种字段约束 主键约束 非空约束 唯一约束 创建索引 添加和删除索引