7.2 Go Map 进阶

发布时间:2026/8/29 17:14:05
7.2 Go Map 进阶 7.2 Go Map 进阶1. Map 的值为切片 —map[K][]Vmap 的值可以是切片实现一个键对应多个值的数据结构packagemainimportfmtfuncmain(){// map[string][]int — 学生名 → 成绩列表studentScores:make(map[string][]int)// 直接赋值切片studentScores[Alice][]int{92,88,95}studentScores[Bob][]int{78,82,85}studentScores[Charlie][]int{90,87,93}// 也可以 append 添加nil 切片 append 安全// studentScores[David] append(studentScores[David], 80)fmt.Println(Student scores:,studentScores)}执行结果Student scores: map[Alice:[92 88 95] Bob:[78 82 85] Charlie:[90 87 93]]要点map[string][]int— 值类型是[]int切片一个学生对应多个成绩赋值方式1直接赋值切片studentScores[Alice] []int{92, 88, 95}赋值方式2逐个 appendstudentScores[Alice] append(studentScores[Alice], 92)nil 切片 append 安全studentScores[David]为 nilappend 自动分配底层数组这是分组模式的基础按键归类多个值2. 嵌套 map — 安全访问两层键嵌套 map 访问时必须逐层检查键是否存在否则可能 panicpackagemainimportfmtfuncmain(){// 嵌套 map科目 → 学生 → 成绩gradebook:make(map[string]map[string]int)// 必须初始化内层 mapgradebook[Math]make(map[string]int)gradebook[Science]make(map[string]int)gradebook[Math][Alice]92gradebook[Math][Bob]85gradebook[Science][Alice]89gradebook[Science][Bob]88// 安全访问两层 comma-ok 检查// 先检查 Math 是否存在再检查 Alice 是否存在mathGrades,mathExists:gradebook[Math]ifmathExists{aliceMath,aliceExists:mathGrades[Alice]ifaliceExists{fmt.Printf(Alices Math grade: %d\n,aliceMath)}}fmt.Println(Gradebook:,gradebook)}执行结果Alices Math grade: 92 Gradebook: map[Math:map[Alice:92 Bob:85] Science:map[Alice:89 Bob:88]]要点make(map[string]map[string]int)— 外层科目内层学生成绩必须初始化内层 mapgradebook[Math] make(map[string]int)不初始化gradebook[Math][Alice] 92会 panic内层是 nil map两层 comma-ok 安全访问第1层mathGrades, mathExists : gradebook[Math]第2层aliceMath, aliceExists : mathGrades[Alice]不安全访问的后果gradebook[English][Alice]— “English” 不存在返回 nil 内层 map写入 panicgradebook[Math][Unknown]— “Unknown” 不存在返回零值 0不 panic但可能误判3. Map 的值为结构体 — 修改需重新赋值map 中结构体值是不可直接修改字段的必须取出 → 修改 → 重新赋值packagemainimportfmtfuncmain(){typePersonstruct{AgeintCitystring}people:make(map[string]Person)people[John]Person{Age:30,City:New York}people[Jane]Person{Age:25,City:Los Angeles}// 错误方式直接修改字段编译报错// people[John].Age 31 // compile error: cannot assign to struct field in map// 正确方式取出 → 修改 → 重新赋值john:people[John]// 取出结构体值拷贝john.Age31// 修改拷贝people[John]john// 重新赋值回 mapfmt.Println(People:,people)}执行结果People: map[Jane:{25 Los Angeles} John:{31 New York}]要点people[John].Age 31—编译报错Go 不允许直接修改 map 中结构体的字段原因map 的值是不可寻址的addressable。people[John]返回的是值的拷贝不是引用正确步骤john : people[John]— 取出值拷贝john.Age 31— 修改拷贝的字段people[John] john— 把修改后的值重新赋值回 map这个限制只针对值类型struct、int 等如果值是指针类型则可以直接修改people:make(map[string]*Person)people[John]Person{Age:30,City:New York}people[John].Age31// 可以指针可寻址也可以用指针 map 避免反复取出赋值map[string]*Person4. Map 模拟集合Set— 去重用map[key]bool的键来模拟集合实现去重packagemainimportfmtfuncmain(){uniqueWords:make(map[string]bool)words:[]string{hello,world,hello,go,world}// 添加到集合键存在即表示该词出现过for_,word:rangewords{uniqueWords[word]true}// 从集合获取所有元素varunique[]stringforword:rangeuniqueWords{uniqueappend(unique,word)}fmt.Println(Unique words:,unique)}执行结果Unique words: [hello world go]要点uniqueWords[word] true— 用 bool 值标记true 表示元素在集合中“hello” 和 “world” 出现两次但 map 键唯一所以只保留一个从集合提取元素遍历 map 的键for word : range uniqueWords集合特性自动去重、快速判断存在uniqueWords[word]返回 true/false遍历顺序不确定输出可能是[hello world go]或[go hello world]5. Map 合并 — 后者覆盖前者合并两个 map 时重复键由后写入的值决定覆盖packagemainimportfmtfuncmain(){map1:map[string]int{a:1,b:2}map2:map[string]int{b:3,c:4}// b 在两个 map 中都存在merged:make(map[string]int)// 先复制 map1fork,v:rangemap1{merged[k]v// merged: {a:1, b:2}}// 再复制 map2b 的值被覆盖fork,v:rangemap2{merged[k]v// merged: {a:1, b:3, c:4} — b:2 被覆盖为 b:3}fmt.Println(Merged maps:,merged)}执行结果Merged maps: map[a:1 b:3 c:4]要点合并方法遍历两个 map依次写入新 mapmap1有b:2map2有b:3合并后merged[b] 3map2 的值覆盖了 map1 的覆盖规则后写入的值覆盖先写入的值如果想保留 map1 的值优先先复制 map2 再复制 map1fork,v:rangemap2{merged[k]v}// map2 先fork,v:rangemap1{merged[k]v}// map1 覆盖 → b:2Go 没有内置的 map 合并函数需要手动遍历合并知识点总结知识点关键概念map 值为切片map[K][]V— 一个键对应多个值nil切片append安全嵌套 mapmap[K1]map[K2]V— 必须逐层初始化内层两层 comma-ok 安全访问map 值为结构体不能直接修改字段必须取出→修改→重新赋值用指针可直接修改map 模拟集合map[K]bool去重键唯一自动去重map 合并依次遍历写入新 map后者覆盖前者重复键由最后写入的值决定