🔖 Go 语言学习教程 · 第 08 篇
📌 本系列基于 Go 1.23 编写,代码兼容 Go 1.21+
全文约 3500 字 | 阅读约 10 分钟
欢迎来到第八篇 👋
上一篇我们学习了数组和切片。今天来学习 Go 的另一种重要数据结构——Map(映射),也就是其他语言中的字典或哈希表。
Map 是键值对的集合,提供了 O(1) 的查找性能。让我们开始吧
✅ 上一篇练习题答案
以下是上一篇练习题的参考答案,欢迎在评论区分享你的解法~
1. 动手实践:创建容量为 4 的切片,append 到容量 16
s := make([]int, 0, 4)
for i := 1; i <= 16; i++ {
s = append(s, i)
fmt.Printf("len=%d, cap=%d
", len(s), cap(s))
}
扩容规律:cap < 256 时翻倍(4→8→16),cap >= 256 时增长 25%。
2. 切片操作:反转整数切片
func reverse(s []int) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
3. 思考题:var s []int 和 s := []int{} 的区别
var s []int:nil 切片,len=0, cap=0,底层数组为 nils := []int{}:空切片,len=0, cap=0,但底层数组非 nil
影响:nil 切片 json.Marshal 输出 null,空切片输出 []。
4. 拓展阅读
Go Blog Go Slices: usage and internals 详细讲解了切片的底层结构和扩容机制。 🚀
一、Map 的创建与初始化
声明与创建
// 声明(nil map,不能直接赋值)
var m1 map[string]int
// make 创建(必须用 make 初始化后才能使用)
m2 := make(map[string]int)
// 字面量初始化
m3 := map[string]int{
"Go": 95,
"Rust": 90,
"Python": 85,
}
💡 nil map 不能写入,会 panic!必须用
make或字面量初始化。
var m map[string]int
m["key"] = 1 // panic: assignment to entry in nil map
📖 二、Map 的基本操作
增删改查
m := make(map[string]int)
// 增/改
m["Go"] = 95
m["Rust"] = 90
m["Go"] = 98 // 覆盖旧值
// 查
score := m["Go"] // 98
score2 := m["Java"] // 0(不存在的键返回零值)
// 安全查找(推荐)
score, ok := m["Go"]
if ok {
fmt.Println("找到了:", score)
}
// 删
delete(m, "Rust")
// 长度
fmt.Println(len(m)) // 1
判断键是否存在
// 正确方式:用两个返回值
if score, ok := m["Go"]; ok {
fmt.Println("Go 的分数是:", score)
} else {
fmt.Println("Go 不在 Map 中")
}
三、遍历 Map
m := map[string]int{"Go": 95, "Rust": 90, "Python": 85}
// range 遍历(顺序不保证)
for k, v := range m {
fmt.Printf("%s: %d\n", k, v)
}
// 只遍历键
for k := range m {
fmt.Println(k)
}
// 只遍历值
for _, v := range m {
fmt.Println(v)
}
💡 Map 遍历顺序是随机的!每次运行结果可能不同。如果需要有序遍历,先提取键再排序。
四、Map 是引用类型
Map 是引用类型,传递时不会拷贝底层数据:
func update(m map[string]int) {
m["Go"] = 100 // 修改会影响原 Map
}
m := map[string]int{"Go": 95}
update(m)
fmt.Println(m["Go"]) // 100 ← 被修改了!
这与切片类似,Map 变量本质上是一个指向底层哈希表的指针。
五、Map 的嵌套
// Map 的 value 可以是另一个 Map
students := map[string]map[string]int{
"张三": {"数学": 95, "英语": 88},
"李四": {"数学": 90, "英语": 92},
}
// 访问嵌套值
fmt.Println(students["张三"]["数学"]) // 95
// 添加新学生(需要先初始化内部 Map)
students["王五"] = map[string]int{"数学": 85, "英语": 90}
📝 六、本篇小结
| 要点 | 总结 |
|---|---|
| 创建 | 必须用 make 或字面量,nil map 不能写入 |
| 查找 | 用 v, ok := m[key] 判断键是否存在 |
| 删除 | delete(m, key) |
| 遍历 | range 遍历,顺序随机 |
| 引用类型 | 传递时不拷贝,修改会影响原 Map |
| 嵌套 | value 可以是 Map、切片等任意类型 |
💬 一句话总结:
Map 是键值对集合,用
make初始化,用v, ok := m[key]安全查找,遍历顺序随机,是引用类型。
✏️ 七、练习题
- ️ 动手实践:创建一个
map[string][]string,存储每个人的爱好列表,并遍历打印。 - 🔧 词频统计:用 Map 统计一段英文文本中每个单词出现的次数。
- 🤔 思考题:为什么 Go 的 Map 遍历顺序是随机的?这是设计缺陷还是有意为之?
- 📚 拓展阅读:查阅 Go Blog 上的 Go Maps in Action。
💡 练习题答案会在下一篇中公布,欢迎在评论区分享你的答案~
关注我,一起学编程
如果本文对你有帮助,欢迎 点赞、在看、转发、关注。