引入
切片用数字索引存取数据,但很多时候需要用名字、ID 这类自定义键来查找数据。Go 的 map 就是用来做这件事的,用键值对保存数据,通过键快速查找值。
正文
定义
定义
map 用键值对保存数据,通过键快速查找值。键类型必须是可比较的(数字、字符串、布尔、数组、结构体等),值类型不限。map 是引用类型,零值是
nil,未初始化的 map 不能写入。
语法
// 字面量创建
m := map[string]int{
"语文": 90,
"数学": 95,
}
// make 创建
m := make(map[string]int)例子
创建和赋值
m := make(map[string]int)
m["语文"] = 90
m["数学"] = 95
fmt.Println(m) // map[数学:95 语文:90]用 make() 初始化后才能写入,字面量创建则不需要 make()。
读取值
m := map[string]int{"a": 1, "b": 2}
fmt.Println(m["a"]) // 1
fmt.Println(m["c"]) // 0(键不存在,返回零值)键不存在时返回值类型的零值,不会报错。
判断键是否存在
m := map[string]int{"a": 1}
v, ok := m["a"]
fmt.Println(v, ok) // 1 true
v, ok = m["b"]
fmt.Println(v, ok) // 0 false用 v, ok := m[key] 的逗号 ok 模式判断键是否存在,ok 为 true 表示存在。
修改值
m := map[string]int{"a": 1}
m["a"] = 100
fmt.Println(m["a"]) // 100对已有的键重新赋值就是修改。
删除键值对
m := map[string]int{"a": 1, "b": 2}
delete(m, "a")
fmt.Println(m) // map[b:2]
fmt.Println(len(m)) // 1delete(m, key) 删除指定键,键不存在也不会报错。
遍历 map
m := map[string]int{
"语文": 90,
"数学": 95,
"英语": 88,
}
for k, v := range m {
fmt.Println(k, v)
}for range 遍历 map,顺序不固定,每次运行可能不同。
map 是引用类型
m1 := map[string]int{"a": 1}
m2 := m1
m2["a"] = 100
fmt.Println(m1["a"]) // 100(跟着变了)map 赋值或传参共享底层数据,修改会互相影响。
nil map
var m map[string]int
fmt.Println(m == nil) // true
// m["a"] = 1 // panic: assignment to entry in nil mapnil map 可以读取(返回零值),但不能写入,写入会 panic。
map 嵌套
scores := map[string]map[string]int{
"Tom": {"语文": 90, "数学": 85},
"Amy": {"语文": 88, "数学": 92},
}
fmt.Println(scores["Tom"]["语文"]) // 90map 的值可以是另一个 map,实现嵌套结构。
用结构体做值
type Student struct {
Name string
Score int
}
m := map[string]Student{
"001": {Name: "Tom", Score: 90},
"002": {Name: "Amy", Score: 85},
}
fmt.Println(m["001"].Name) // Tommap 的值可以是任意类型,包括结构体。
常见写法
| 写法 | 说明 |
|---|---|
m := map[K]V{…} | 字面量创建 |
m := make(map[K]V) | make() 创建 |
m[key] = v | 新增/修改 |
v := m[key] | 读取(不存在返回零值) |
v, ok := m[key] | 读取并判断是否存在 |
delete(m, key) | 删除键值对 |
len(m) | 获取键值对数量 |
for k, v := range m | 遍历 |
特点
- map 用键值对保存数据,通过键快速查找
- 键类型必须可比较,切片、map、函数不能做键
- 键不存在时返回值类型的零值,用逗号 ok 模式判断是否存在
delete()删除键值对,键不存在不报错for range遍历顺序不固定- map 是引用类型,赋值和传参共享数据
nilmap 不能写入,必须先make()或字面量初始化- map 不是并发安全的,并发读写需要加锁或用
sync.Map
理解
map 就像一个字典,给每个数据贴一个标签(键),通过标签就能快速找到数据。用起来很直觉:创建、存、取、删,四个操作就能覆盖大部分场景。要注意的是 map 是引用类型,赋值后修改会互相影响,还有并发读写要加锁。
引出
map 能用键存取数据,但如果想把不同类型的数据组合成一个整体,接下来看 Go 结构体,学习怎么把相关数据打包在一起。