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)

关键点:

  1. 引用类型:赋值和传参共享底层数据
  2. nil Map:nil map不能写入
  3. 键类型:必须是可比较类型
  4. 无序:遍历顺序随机
  5. 并发不安全:需要加锁或使用sync.Map

准备好学习Map操作了吗?让我们进入下一章!

最后更新:2026-03-26