Map

映射Map是一个存储键值对的无序集合,映射Map是一种巧妙并且实用的数据结构。它是一个无序的key/value对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。

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

  1. Map的声明

    1. var m map[string] string

    m是声明的变量名,sting是对应的Key的类型,string是value的类型。

  2. 创建

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

  1. m := make(map[string]int)

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

  1. m := map[string]int{
  2. "keke": 001,
  3. "jame": 002,
  4. }

这个等价于:

  1. m := make(map[string]int)
  2. m["keke"] = 001
  3. m["jame"] = 002

另外一种创建map的方式是map[string]int{}。

3.元素的删除

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

  1. delete(ages, "jame") //可以删除m["jame"]

而且x += y和x++等简短赋值语法也可以用在map上,所以上面的代码可以改写成:

  1. ages["keke"] += 1

更简单的写法:

  1. m["keke"]++

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

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

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

要想遍历map中全部的key/value对的话,可以使用range风格的for循环实现,和之前的slice遍历语法类似。下面的迭代语句将在每次迭代时设置name和age变量,它们对应下一个键/值对:

  1. for k, v := range m {
  2. fmt.Printf("%s\t%d\n", k, v)
  3. }

Map的迭代顺序是不确定的,并且不同的哈希函数实现可能导致不同的遍历顺序。在实践中,遍历的顺序是随机的,每一次遍历的顺序都不相同。这是故意的,每次都使用随机的遍历顺序可以强制要求程序不会依赖具体的哈希函数实现。如果要按顺序遍历key/value对,我们必须显式地对key进行排序,可以使用sort包的Strings函数对字符串slice进行排序。常见的处理方式:

  1. import "sort"
  2. var names []string
  3. for name := range ages {
  4. names = append(names, name)
  5. }
  6. sort.Strings(names)
  7. for _, name := range names {
  8. fmt.Printf("%s\t%d\n", name, ages[name])
  9. }

map类型的零值是nil,也就是没有引用任何映射Map。

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