maps 标准库与 cmp(1.21+)
本教程共 80 篇 · 第 35 篇 · 更新于 2026-07-27 · 约 6 分钟阅读
35. maps 标准库与 cmp(1.21+)
本节目标:学会用 Go 1.21 的 maps 标准库克隆 map、提取 key/value,以及用 cmp 包做类型安全的比较。
maps 标准库
和 slices 包一样,maps 也是 Go 1.21 引入的标准库,把以前手写的 map 操作收编了。
Notemaps 包需要 Go 1.21 及以上版本。它大量使用了泛型,所以能适配各种 key 和 value 类型。
maps.Clone:克隆 map
Clone 创建一个独立的 map 副本:
package main
import (
"fmt"
"maps"
)
func main() {
original := map[string]int{
"apple": 5,
"banana": 3,
}
copied := maps.Clone(original)
copied["apple"] = 100
fmt.Println(original["apple"]) // 5 原map没变
fmt.Println(copied["apple"]) // 100 副本独立
}
以前克隆 map 得自己写循环:
// 老办法
copied := make(map[string]int, len(original))
for k, v := range original {
copied[k] = v
}
现在一行 maps.Clone(original) 搞定。
Warning
Clone是浅拷贝。如果 value 是引用类型(切片、map、指针),副本和原件会共享底层数据。
maps.Keys 和 maps.Values:提取键和值
Keys 返回所有 key 组成的切片,Values 返回所有 value 组成的切片:
package main
import (
"fmt"
"maps"
"slices"
)
func main() {
m := map[string]int{
"apple": 5,
"banana": 3,
"cherry": 8,
}
keys := maps.Keys(m)
values := maps.Values(m)
// Go 1.23+ 返回迭代器,用 slices.Sorted 收集并排序
// Go 1.21-1.22 直接返回切片,用 slices.Sort 排序
fmt.Println(slices.Sorted(keys)) // [apple banana cherry]
fmt.Println(slices.Sorted(values)) // [3 5 8]
}
Tip在 Go 1.23 中,
maps.Keys和maps.Values返回的是迭代器(iterator)。可以用slices.Collect收集成切片,或用slices.Sorted收集并排序。在 Go 1.21-1.22 中,这两个函数直接返回切片,排序用slices.Sort。
maps.Copy:批量复制
Copy 把 src 的所有键值对复制到 dst,已存在的 key 会被覆盖:
package main
import (
"fmt"
"maps"
)
func main() {
dst := map[string]int{"a": 1, "b": 2}
src := map[string]int{"b": 20, "c": 30}
maps.Copy(dst, src)
fmt.Println(dst) // map[a:1 b:20 c:30]
}
适合用来做配置合并:把多个小 map 合并成一个大 map。
maps.Equal:比较两个 map
m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]int{"a": 1, "b": 2}
m3 := map[string]int{"a": 1, "b": 3}
fmt.Println(maps.Equal(m1, m2)) // true
fmt.Println(maps.Equal(m1, m3)) // false
maps.EqualFunc:自定义比较
如果 value 是不可比较的类型(比如切片),用 EqualFunc 传入自定义比较函数:
m1 := map[string][]int{"a": {1, 2}}
m2 := map[string][]int{"a": {1, 2}}
fmt.Println(maps.EqualFunc(m1, m2, slices.Equal)) // true
maps.DeleteFunc:条件删除
DeleteFunc 删除所有满足条件的键值对:
package main
import (
"fmt"
"maps"
)
func main() {
m := map[string]int{
"apple": 5,
"banana": 3,
"cherry": 8,
"date": 2,
}
// 删除所有值小于5的
maps.DeleteFunc(m, func(k string, v int) bool {
return v < 5
})
fmt.Println(m) // map[apple:5 cherry:8]
}
cmp 包:类型安全的比较
cmp 包也是 Go 1.21 新增的,提供了两个核心东西。
cmp.Ordered 约束
cmp.Ordered 是一个类型约束,包含所有支持排序的类型:
// cmp.Ordered 包含的类型
// ~int ~int8 ~int16 ~int32 ~int64
// ~uint ~uint8 ~uint16 ~uint32 ~uint64 ~uintptr
// ~float32 ~float64
// ~string
你在写泛型函数时,如果需要对参数做排序或比较,用 cmp.Ordered 做约束就行。
cmp.Compare 函数
Compare 返回两个值的比较结果:
- 返回负数:a < b
- 返回 0:a == b
- 返回正数:a > b
package main
import (
"cmp"
"fmt"
)
func main() {
fmt.Println(cmp.Compare(1, 2)) // -1
fmt.Println(cmp.Compare(2, 2)) // 0
fmt.Println(cmp.Compare(3, 2)) // 1
fmt.Println(cmp.Compare("apple", "banana")) // -1 字符串也能比
}
在写排序比较函数时特别好用:
type Person struct {
Name string
Age int
}
people := []Person{{"Bob", 25}, {"Alice", 30}}
slices.SortFunc(people, func(a, b Person) int {
return cmp.Compare(a.Age, b.Age) // 按年龄排序
})
cmp.Less 函数
Less 就是 Compare(a, b) < 0 的简写:
fmt.Println(cmp.Less(1, 2)) // true
fmt.Println(cmp.Less(2, 1)) // false
小结
Go 1.21 的 maps 和 cmp 包让 map 操作和比较操作现代化了:
maps.Clone一行克隆 mapmaps.Keys/maps.Values提取键值maps.Copy合并 mapmaps.Equal/EqualFunc比较 mapcmp.Compare类型安全的比较cmp.Ordered排序类型约束
下一部分进入指针和结构体,搞懂 Go 的值语义和引用语义。