Golang 语法速通指南(七)复合数据结构之 Map
用过 C++ 的 STL 的人肯定见过 Map,或者说这东西相当于 Python 中的字典
简单地说,就是用来存储键值对的结构,键(key)必须是可比较类型,而值(value)可以是任意类型
创建 Map
var
1 | var m map[string]int |
使用 make
1 | m = make(map[string]int) |
使用字面值
1 | m = map[string]int{"one": 1, "two": 2} |
当然你可以指定内容为空
1 | m = map[string]int{} |
通过使用空接口,你可以在同一个 map 中存储不同类型的 value(就像 Python 中的字典一样)
1 | m = map[string]interface{}{ |
当然现在空接口有一个语法糖 any
,不够我还是习惯旧的写法
添加元素
直接使用索引添加
1 | ages["alice"] = 31 |
访问 Map
直接使用索引访问
1 | fmt.Println(ages["alice"]) // "32" |
如果你尝试访问一个不存在的键,会返回零值
如果你愿意接收两个返回值,那么会返回结果和是否存在的 bool
所以你会经常看见这样的写法
1 | if age, ok := ages["bob"]; !ok { /* ... */ } |
另外一种是使用 for k,v:= range m
来迭代,分别取出其中的 key 和 value
但是需要注意的是,迭代出来的顺序是乱的
当然你可以只接收一部分,例如 for _,v:= range m
修改元素
-
直接拿出来修改
1
ages["bob"] = ages["bob"] + 1
-
如果你的值是个结构体等复杂结构,你不能修改结构体中的内部值,只能构造一个新的结构体然后重新给map赋值
-
和切片一样,使用
for k,v:= range m
时,修改v
是没有用的,你必须使用m[k]
来修改
删除元素
使用内置的 delete
函数
1 | delete(ages, "alice") |
开发常见问题
比较两个 Map
和切片一样,Map 直接不能直接使用 ==
来比较,除了和 nil
来比较
你只能手动遍历来比较
1 | func equal(x, y map[string]int) bool { |
Golang 中有没有 Set?
没有,你可以使用值为 bool 的 map 来模拟 set
一个小技巧
map 的 key 必须是可以比较的,所以你不能直接创建一个 key 是切片的 map
但是你可以通过一个辅助函数将其转换成可比较的类型,再封装一层
1 | var m = make(map[string]int) |
使用同样的技术可以处理任何不可比较的 key 类型,而不仅仅是 slice 类型
这种技术对于想使用自定义 key 比较函数的时候也很有用,例如在比较字符串的时候忽略大小写
有没有清空的方法?
暂时无,请使用 range 然后一个一个删除