map是散列表的引用,map的类型为map[K]V,K和V是字典的键和值对应的数据类型,
map中所有的键都拥有相同的数据类型,同时所有的值都拥有相同的数据类型,
但键的类型和值的类型不一定相同
键的类型K必须是可以通过操作符==来进行比较的数据类型,
所以map可以检测某一个键是否已经存在
初始化
- 内置函数make创建
ages := make(map[string]int) // 创建一个从string到int的map
- 使用map的字面量来新建一个带初始化键值对元素的字典
ages := map[string]int {
"alice": 31,
"charlie": 34,
}
等价于
ages := make(map[string]int)
ages["alice"] = 31
ages["charlie"] = 34
元素访问
通过下标的方式
ages["alice"] = 32
如果map使用给定的键查找的元素不存在,就返回类型的零值,例如
// ages["bob"]的值是0
ages["bob"]++
但是map元素不是一个变量,不可以获取它的地址
_ = &ages["bob"] // 编译错误,无法获取map元素的地址
原因是map的增长可能会导致已有元素被重新散列到新的存储位置,
这样就可能使得获取的地址无效
可以使用for循环来遍历map中所有的键和对应的值
for name, age := range ages {
fmt.Printf("%s\t%d\n", name, age)
}
map中元素迭代顺序是不固定的,不同的实现方法会使用不同的散列算法
移除元素
使用内置函数delete
delete(ages, "alice")
即使键不在map中,上面的操作也是安全的
零值
map的零值是nil
,也就是说没有引用任何散列表
var ages map[string]int
fmt.Println(ages == nil) // "true"
fmt.Println(len(ages) == 0) // "true"
向零值map中设置元素会导致错误
ages["carol"] = 21 // 宕机:为零值map中的项赋值
判断一个元素是够在map中
if age, ok := ages["bob"]; !ok { /* ... */ }
比较
和slice
一样,map不可以比较,唯一合法的比较就是和nil
做比较,
为了判断两个map是否拥有相同的键和值,必须写一个循环
func equal(x, y map[string]int) bool {
if len(x) != len(y) {
return false
}
for k, xv := range x {
if yv, ok := y[k]; !ok || yv != xv {
return false
}
}
return true
}
总结
- 如果map使用给定的键查找的元素不存在,就返回类型的零值
- map元素不是一个变量,不可以获取它的地址
- map中元素迭代顺序是不固定的
- map不可以比较,唯一合法的比较就是和
nil
做比较