Map基础 #
一、Map概述 #
Map是一种键值对集合,通过键快速查找值。
1.1 Map特点 #
- 键值对存储
- 键唯一
- 无序
- 引用类型
二、Map声明 #
2.1 声明未初始化 #
go
var m map[string]int
fmt.Println(m == nil) // true
2.2 make初始化 #
go
m := make(map[string]int)
m["one"] = 1
fmt.Println(m) // map[one:1]
2.3 字面量初始化 #
go
m := map[string]int{
"one": 1,
"two": 2,
"three": 3,
}
fmt.Println(m)
2.4 指定初始容量 #
go
m := make(map[string]int, 100) // 初始容量100
三、基本操作 #
3.1 添加元素 #
go
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
3.2 获取元素 #
go
m := map[string]int{"one": 1, "two": 2}
v := m["one"]
fmt.Println(v) // 1
3.3 检查键是否存在 #
go
m := map[string]int{"one": 1, "two": 2}
v, ok := m["three"]
fmt.Println(v, ok) // 0 false
if v, ok := m["one"]; ok {
fmt.Println("存在:", v)
}
3.4 修改元素 #
go
m := map[string]int{"one": 1}
m["one"] = 10
fmt.Println(m) // map[one:10]
3.5 删除元素 #
go
m := map[string]int{"one": 1, "two": 2}
delete(m, "one")
fmt.Println(m) // map[two:2]
3.6 获取长度 #
go
m := map[string]int{"one": 1, "two": 2}
fmt.Println(len(m)) // 2
四、Map遍历 #
4.1 for-range遍历 #
go
m := map[string]int{"one": 1, "two": 2, "three": 3}
for key, value := range m {
fmt.Printf("%s: %d\n", key, value)
}
4.2 只遍历键 #
go
for key := range m {
fmt.Println(key)
}
4.3 只遍历值 #
go
for _, value := range m {
fmt.Println(value)
}
4.4 遍历顺序 #
Map遍历顺序是随机的:
go
m := map[string]int{"a": 1, "b": 2, "c": 3}
for k, v := range m {
fmt.Println(k, v) // 顺序不确定
}
4.5 有序遍历 #
go
m := map[string]int{"b": 2, "a": 1, "c": 3}
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("%s: %d\n", k, m[k])
}
五、Map是引用类型 #
5.1 赋值共享底层数据 #
go
m1 := map[string]int{"one": 1}
m2 := m1
m2["two"] = 2
fmt.Println(m1) // map[one:1 two:2]
fmt.Println(m2) // map[one:1 two:2]
5.2 函数传参 #
go
func modify(m map[string]int) {
m["new"] = 100
}
func main() {
m := map[string]int{"one": 1}
modify(m)
fmt.Println(m) // map[new:100 one:1]
}
六、Map的键类型 #
6.1 可比较类型 #
键必须是可比较的类型:
- 基本类型:int、float、string、bool
- 指针
- 接口
- 结构体(如果所有字段可比较)
- 数组(如果元素可比较)
6.2 不可比较类型 #
以下类型不能作为键:
- 切片
- Map
- 函数
go
// 错误:切片不能作为键
m := make(map[[]int]int)
// 正确:字符串可以作为键
m := make(map[string]int)
七、嵌套Map #
7.1 Map的值是Map #
go
m := map[string]map[string]int{
"group1": {"a": 1, "b": 2},
"group2": {"c": 3, "d": 4},
}
fmt.Println(m["group1"]["a"]) // 1
7.2 初始化嵌套Map #
go
m := make(map[string]map[string]int)
m["group1"] = make(map[string]int)
m["group1"]["a"] = 1
八、实际应用 #
8.1 计数器 #
go
func countWords(words []string) map[string]int {
counts := make(map[string]int)
for _, word := range words {
counts[word]++
}
return counts
}
8.2 缓存 #
go
var cache = make(map[string]string)
func getWithCache(key string) string {
if v, ok := cache[key]; ok {
return v
}
v := fetchFromDB(key)
cache[key] = v
return v
}
8.3 分组 #
go
func groupBy(items []Item, keyFunc func(Item) string) map[string][]Item {
groups := make(map[string][]Item)
for _, item := range items {
key := keyFunc(item)
groups[key] = append(groups[key], item)
}
return groups
}
九、常见错误 #
9.1 nil Map #
go
var m map[string]int
m["key"] = 1 // panic: assignment to entry in nil map
9.2 并发访问 #
go
var m = make(map[string]int)
go func() {
m["key"] = 1 // 并发写入
}()
m["key"] = 2 // 并发写入,可能panic
十、总结 #
Map要点:
| 操作 | 方法 |
|---|---|
| 创建 | make(map[K]V) |
| 添加/修改 | m[key] = value |
| 获取 | v := m[key] |
| 检查存在 | v, ok := m[key] |
| 删除 | delete(m, key) |
| 长度 | len(m) |
关键点:
- 引用类型:赋值和传参共享底层数据
- nil Map:nil map不能写入
- 键类型:必须是可比较类型
- 无序:遍历顺序随机
- 并发不安全:需要加锁或使用sync.Map
准备好学习Map操作了吗?让我们进入下一章!
最后更新:2026-03-26