数组与切片通过数字索引访问数据,map 则通过“键”查找“值”。本课用姓名查成绩,学习增删改查、判断键是否存在、遍历及 nil map。
按 main.go 中的 1~7 节逐段手敲。本课共享根目录的 go.mod,仅使用标准库,不需要新增依赖。
scores := map[string]int{
"小朱": 90,
"小李": 75,
}
map[string]int 表示键是 string,值是 int。键唯一,给已有键赋值会覆盖原值,不会产生第二份同名记录。
多行复合字面量中,最后一项后面也需要逗号。
另一种方式是先创建空 map,再写入:
scores := make(map[string]int)
scores["小朱"] = 90
map 的键必须是可比较类型;本课先使用字符串。整数也可以做键,切片和 map 本身不能做键。
| 操作 | 示例 |
|---|---|
| 新增或修改 | scores["小李"] = 80 |
| 读取 | score := scores["小李"] |
| 判断是否存在 | score, ok := scores["小李"] |
| 删除 | delete(scores, "小李") |
| 元素数量 | len(scores) |
读取不存在的键会得到值类型的零值,不会自动创建这个键。因此值为 0 不代表键不存在,需要用 ok 判断。
删除不存在的键不会报错。map 没有切片那样的 append,新增直接通过键赋值,也不能用 cap 查询容量。
if score, ok := scores["小李"]; ok {
fmt.Println(score)
} else {
fmt.Println("没有找到")
}
分号前是查询并声明变量,分号后才是布尔条件。这里的 score、ok 只在整个 if / else 语句内有效,不会泄漏到语句外。
for name, score := range scores {
fmt.Println(name, score)
}
不能依赖 map 的插入顺序,也不能假设连续两次遍历顺序相同。本例直接遍历时只做总分统计,不依赖顺序。
如果需要按指定顺序显示,可以准备一个姓名切片逐项查询;如果需要自动排序,可在后续学习标准库 sort 后先排序键。直接打印整个 map 的表现不能代替对 range 顺序的理解。
var scores map[string]int
此时 scores == nil,长度为 0。读取得到零值,查询存在性得到 false,delete 也安全,但直接写入会触发运行时 panic。应先使用 make 或 map 字面量初始化。
alias := scores
对已初始化的 map 做这样的赋值不会独立复制元素,通过 alias 修改条目会影响 scores。需要独立副本时,应新建 map 并循环复制;未来涉及切片或指针值时还要区分浅拷贝和深拷贝。
在仓库根目录执行:
New-Item -ItemType Directory -Force bin/06_maps | Out-Null
go build -o ./bin/06_maps/maps.exe ./lessons/06_maps
.\bin\06_maps\maps.exe
修改源码后需要重新编译。快速编译并运行:
go run ./lessons/06_maps
也可以从根目录进入本课:
Set-Location lessons/06_maps
go run .
=== 创建与查询 ===
学生数量:3
小朱的成绩:90
=== 新增与修改 ===
新增小陈:88,修改小李:80
学生数量:4
=== 判断键是否存在 ===
直接查询小赵:0
查询小王:成绩=0,存在=true
查询小赵:成绩=0,存在=false
找到小李,成绩:80
=== 删除 ===
删除后小王存在:false,学生数量:3
=== 遍历与统计 ===
总分:258
平均分:86.00
小朱:90
小李:80
小陈:88
=== nil 与 make ===
初始化前:nil=true,长度=0,读取结果=false
初始化后:nil=false,复习完成=true
=== 赋值与共享 ===
通过 alias 修改后,小朱的原成绩也变为:95
len 和总分如何变化。ok。for name, score := range scores 输出,理解顺序不保证固定。_, ok := ... 检查是否还存在。增加或删除学生后,固定姓名切片不会自动更新,需要同步调整。默认代码在修改 alias 前已经统计过总分,所以修改发生后,如需新总分,应重新计算。
若要另外手敲,放进本课 practice/ 子目录,用 go run ./lessons/06_maps/practice 运行,不要在同一个包里重复声明 main。
下一课建议正式学习函数:参数、返回值与多返回值,把计算逻辑拆分成可复用的小块。