1. map的概念

了解Map之前,先了解下哈希表。
哈希表是一种巧妙并且实用的数据结构。它是一个无序的key/value对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。

在Go语言中,一个map就是一个哈希表的引用,map类型可以写为map[K]V,其中K和V分别对应key和value。map中所有的key都有相同的类型,所有的value也有着相同的类型,但是key和value之间可以是不同的数据类型。其中K对应的key必须是支持==比较运算符的数据类型,所以map可以通过测试key是否相等来判断是否已经存在。

2. 创建map

内置的make函数可以创建一个map:

ages := make(map[string]int)

我们也可以用map字面值的语法创建map,同时还可以指定一些最初的key/value:

ages := map[string]int{
    "alice":   31,
    "charlie": 34,
}

这相当于:

ages := make(map[string]int)
ages["alice"] = 31
ages["charlie"] = 34

3. 删除map元素

使用内置的delete函数可以删除元素:

delete(ages, "alice")

4. 遍历map

for name, age := range ages {
    fmt.Printf("%s\t%d\n", name, age)
}

5. map注意事项

5.1 map元素不能取址

map中的元素并不是一个变量,因此我们不能对map的元素进行取址操作:

_ = &ages["bob"] // compile error: cannot take address of map element

禁止对map元素取址的原因是map可能随着元素数量的增长而重新分配更大的内存空间,从而可能导致之前的地址无效。

5.2 map的零值

map类型的零值是nil,也就是没有引用任何哈希表。

var ages map[string]int
fmt.Println(ages == nil)    // "true"
fmt.Println(len(ages) == 0) // "true"

map上的大部分操作,包括查找、删除、len和range循环都可以安全工作在nil值的map上,它们的行为和一个空的map类似。
但是,注意,向一个nil值的map存入元素将导致一个panic异常

ages["carol"] = 21 // panic: assignment to entry in nil map

在向map存数据前必须先创建map。

5.3 map之间的比较

和slice一样,map之间也不能进行相等比较;唯一的例外是和nil进行比较。
要判断两个map是否包含相同的key和value,我们必须通过一个循环实现:

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
}