map 是经常被使用的内置 key-value 型容器,是一个同类型元素的无序组,元素通过另一类型唯一键进行索引。
其键可以是任何支持相等性操作符的类型, 如整数、浮点数、复数、字符串、指针、接口(只要其动态类型支持相等性判断)、结构以及数组。 因此键类型不能是函数、映射或切片,因为它们的相等性还未定义。当然,slice 和 map 的比较可以使用reflect.DeepEqual(sl0, sl1)
和reflect.DeepEqual(m0, m1)
。
与切片一样,映射也是引用类型。若将映射传入函数中,并更改该映射的内容,则修改对调用者同样可见。
使用示例:
package main
import "fmt"
func main() {
nameAge := make(map[string]int)
nameAge["bob"] = 18 //增
nameAge["tom"] = 16 //增
delete(nameAge, "bob") //删
nameAge["tom"] = 19 //改
v := nameAge["tom"] //查
fmt.Println("v=",v)
v, ok := nameAge["tom"] //查,推荐用法
if ok {
fmt.Println("v=",v,"ok=",ok)
}
for k, v :=range nameAge { //遍历
fmt.Println(k, v)
}
}
输出结果:
v= 19
v= 19 ok= true
tom 19
未初始化的 map 其零值为 nil,可以使用内建函数 make 定义一个 map 变量。
// 申明一个值为 nil 的 map 变量
var m map[T1]T2
// 创建 0 容量的 map
var m = make(map[T1]T2)
var m = map[T1]T2{}
// 创建指定容量的 map
var m = make(map[T]T2, hint)
// 创建并初始化 map
var m = map[string]int {
"dable" : 27,
"cat" : 28,
}
注意: 在定义 map 时可以省略容量,超出容量时会自动扩容,但尽量提供一个合理的初始值。注意指定的容量只是一个提示,map 并没有一个具体的容量,所以我们无法使用 cap() 函数来获取一个 map 的容量。
// 错误示例
func main() {
m := make(map[string]int, 100)
println(cap(m)) // error: invalid argument m (type map[string]int) for cap
}
另外可以使用 len() 获取元素个数。键值对不存在时会自动添加,使用 delete() 可以删除某键值对。
(1)遍历所有 key。
// 方式一(推荐)
for k := range mapVar {
...
}
// 方式二
for k, _ := range mapVar {
...
}
(2)遍历所有 value。
for _, v := range mapVar {
...
}
(3)遍历所有 key 与 value。
for k, v := range mapVar {
...
}
注意,map 在没有被修改的情况下,使用 range 多次遍历 map 时输出的 key 和 value 的顺序可能不同。这是 Go 语言的设计者们有意为之,在每次 range 时的顺序被随机化,旨在提示开发者们,Go 底层实现并不保证 map 遍历顺序稳定,请大家不要依赖 range 遍历结果顺序。Golang 官方博文对此有详细说明:Go maps in action。
向 map 写入元素时,键值对不存在时会自动添加,键值存在时将被新值覆盖。
// 新增或修改
m["name"] = "wade"
使用 delete() 删除某键值对。
// 删除,key 不存在则啥也不干
delete(m, "name")
// 可遍历删除
for k, v := range m {
if k or v 满足条件 {
delete(m, "name")
}
}
// 三种查询方式
v := m["name"] // key 不存在返回 value 类型的零值
v, ok := m["name"]
_, ok := m["name"]
// 方式一
for k := range mapVar {
...
}
// 方式二(不推荐)
for k, _ := range mapVar {
...
}
for _, v := range mapVar {
...
}
for k, v := range mapVar {
...
}