练习
学完本章你应该掌握
- 能定义结构体类型,完成结构体实例的初始化、字段读写和基础方法调用。
- 能在切片、
map、函数和条件判断中自然使用结构体组织业务数据,而不是继续用零散变量硬拼。 - 能理解结构体嵌入的作用,知道它是组合复用而不是传统面向对象里的“类继承”。
- 能区分值参数、指针参数、值接收者和指针接收者在“是否修改原结构体”上的差异,并写对对应代码。
- 能为结构体字段添加
tag与json tag,控制 JSON 字段名、忽略字段和零值省略行为。 - 能识别并修正结构体章节的常见错误,例如字段名大小写、初始化语法、修改不生效、tag 写了却不输出等问题。
简单
第 1 题:定义并输出一张学生卡
编写一个 Go 程序,完成下面要求:
- 定义结构体
Student - 字段包括:
Name string、Age int、Score float64 - 创建一个学生:
Name是小李Age是18Score是92.5 - 分别输出这三个字段
期望输出类似这样:
| |
查看参考答案
| |
第 2 题:补全结构体字面量
已知下面的结构体:
| |
请补全下面代码中的空白,让程序输出:
| |
| |
查看参考答案
补全后的代码如下:
| |
说明:结构体字面量初始化时,字段名和值之间写 :,每一行字段后面要记得写逗号。
第 3 题:给结构体绑定一个方法
编写一个 Go 程序,完成下面要求:
- 定义结构体
User - 字段包括:
Name string、City string - 给它绑定一个方法
PrintProfile() - 调用这个方法后输出:
| |
查看参考答案
| |
说明:func (u User) PrintProfile() 里的 (u User) 是接收者,表示这个方法属于 User 类型。
第 4 题:修正一段结构体代码
下面程序有两个明显问题,请改正后让它正常运行,并输出商品价格。
| |
查看参考答案
修正后的代码如下:
| |
两个问题分别是:
- 结构体字面量里每个字段后面要有逗号,所以
Name: "机械键盘"这一行后面漏了逗号。 - 字段名是
Price,访问时也要写product.Price,不能写成不存在的product.price。
第 5 题:用函数接收结构体并返回简介
编写一个 Go 程序,完成下面要求:
- 定义结构体
Course - 字段包括:
Title string、Hours int - 编写函数
buildSummary(c Course) string - 让这个函数返回类似下面的文字:
| |
- 在
main中创建一个课程并调用这个函数
查看参考答案
| |
说明:这道题把结构体和前面学过的函数放到了一起,让“多个字段的数据”可以整体传给函数处理。
一般
第 6 题:用结构体切片统计成绩
编写一个程序,完成下面要求:
- 定义结构体
Student - 字段包括:
Name string、Score int - 准备下面这组数据:
| |
- 使用
for range遍历这组结构体数据 - 统计及格人数
passCount - 统计平均分
avg,保留 1 位小数
期望输出类似这样:
| |
查看参考答案
| |
说明:这道题的重点是把一组“相关字段”装进结构体,再配合切片和循环做统计,而不是继续维护多组并行变量。
第 7 题:使用结构体嵌入复用字段和方法
编写一个 Go 程序,完成下面要求:
- 定义结构体
People,字段为City string - 给
People绑定方法PrintCity(),输出城市:北京 - 定义结构体
Employee - 让
Employee匿名嵌入People - 再增加字段:
Name string、Role string - 创建一个员工并完成下面两件事:
输出
员工:小刘,角色:开发直接调用employee.PrintCity()
查看参考答案
| |
说明:Employee 并不是“继承了一个类”,而是通过嵌入 People 复用了字段和方法。
第 8 题:用指针参数给用户过生日
编写一个程序,完成下面要求:
- 定义结构体
User - 字段包括:
Name string、Age int - 编写函数
birthday(u *User) - 这个函数的作用是让用户年龄加
1 - 在
main中先输出年龄,再调用函数,再输出年龄
期望输出类似这样:
| |
查看参考答案
| |
说明:如果这里把参数写成 User 而不是 *User,函数里改到的只是副本,外面的 user.Age 不会变化。
第 9 题:把值接收者改成指针接收者
下面程序想给商品补库存,但现在补完以后库存没有变化。
请改正代码,让它最终输出:
| |
| |
查看参考答案
修正后的代码如下:
| |
关键点:
- 原来的
func (g Goods) AddStock是值接收者,修改的是副本。 - 改成
func (g *Goods) AddStock以后,方法内部改到的就是原结构体。 - 调用时写
goods.AddStock(5)就可以,Go 会自动帮你取地址。
第 10 题:按姓名查询学生信息
编写一个程序,完成下面要求:
- 定义结构体
Student - 字段包括:
Name string、Age int、Score int - 准备一张
map[string]Student - 数据如下:
| |
- 读取一个姓名
- 如果存在,输出:
| |
- 如果不存在,输出:
| |
查看参考答案
| |
说明:这道题把结构体和前面学过的 map、输入、if 初始化语句; 条件 放到了一起,很接近真实的数据查询场景。
进阶
下面四题会把结构体和指针、切片、函数、encoding/json 放到更接近真实数据组织的场景里,重点考察多个知识点的配合使用。
第 11 题:为文章结构体添加 json tag
编写一个程序,完成下面要求:
- 定义结构体
Article - 字段包括:
Title string、Author string、ViewCount int - 给它们添加合适的
json tag - 要求序列化后的 JSON 字段名分别是:
titleauthorview_count - 创建一篇文章并转成 JSON 输出
期望输出类似这样:
| |
查看参考答案
| |
说明:json tag 不会改变结构体字段本身的名字和类型,它只是告诉 encoding/json 在序列化时应该用什么 JSON 字段名。
第 12 题:使用 json:"-" 和 omitempty 导出用户资料
编写一个程序,完成下面要求:
- 定义结构体
Profile - 字段包括:
Name stringAge intPassword stringPhone string - JSON 规则如下:
Name输出成nameAge输出成age,但如果是零值则省略Password永远不要出现在 JSON 中Phone输出成phone,但如果是空字符串则省略 - 创建下面这个值:
| |
- 把它转成 JSON 并输出
期望输出:
| |
查看参考答案
| |
说明:
json:"-"表示这个字段永远不参与 JSON 编码。omitempty表示字段是零值时省略输出,0、""、false都可能被省略。
第 13 题:修正 tag 写了却没有输出的问题
下面程序希望输出:
| |
但它现在输出的是:
| |
请改正代码,让 JSON 正常包含姓名和年龄。
| |
查看参考答案
修正后的代码如下:
| |
原因说明:
encoding/json只能处理可导出的字段,也就是首字母大写的字段。- 原来的
name和age虽然写了 tag,但字段本身是小写,仍然不会被 JSON 编码。 tag只是附加说明,不能替代“字段需要导出”这条规则。
第 14 题:实现一个班级成绩报告
请完成一个稍微完整一点的小场景:
- 定义结构体
Student - 字段包括:
Name stringScore intComment string - 给这三个字段添加合适的
json tag - 其中
Comment为空时不输出到 JSON - 给
Student绑定一个指针接收者方法AddBonus(points int),用于给分数加分 - 准备下面这组学生数据:
| |
- 遍历这组数据:
如果学生分数小于
60,就给他加5分 统计最终的及格人数passCount统计最终平均分avg - 最后把更新后的学生切片转成 JSON 输出
期望输出类似这样:
| |
查看参考答案
| |
说明:
- 这里使用
for i := range students,是为了直接修改切片里的原始结构体元素。 - 如果写成
for _, student := range students,拿到的是每个元素的副本,修改时很容易和预期不一致。 - 这道题把结构体、指针接收者、切片遍历、判断统计和 JSON 输出都串起来了,比较接近真实业务中的数据处理流程。