038-Map 结构

大多数编程语言都提供了 Hash 表这种数据结构,比如 C++ 的 map/unorder_map,python 的 dict 等。hash 表是一种相当神奇且有用的数据结构,平时写代码的时候,几乎处处能遇到它的身影。在 Go 里,使用 map 这种数据结构引用底层的 hash 表。

1. 声明与定义

下面这四种试可以创建 map,它的 key 类型是 string,value 类型是 int

a := make(map[string]int) // 创建空 map
b := map[string]int{}     // 同上
c := map[string]int{      // 通过字面量创建 map 
    "allen": 20,
    "luffy": 19,          // 最后一个 kv 后面的『逗号』可不能少
}
var d map[string]int      // 创建空 map,不过不同于 a 和 b

上面 a, b, d 三种都是创建空 map,但是 d 最与众不同。d 的引用指向的是 nil 值,因此它也没有指向任何 hash 表,底层的空间也不存在。看下面的例子:

a["allen"] = 10 // ok
b["allen"] = 10 // ok
c["allen"] = 10 // ok
d["allen"] = 10 // 运行时异常

注意上面的赋值过程,即使一开始 "allen" 这个 key 不存在也没关系,如果不存在即插入。

2. 访问元素和遍历 map

假设有如下 map:

ages := map[string]int {
    "allen": 20,
    "luffy": 19,
    "zoro": 20,
    "sanji":20,
}
  • 访问元素
fmt.Printf("allen: %d\n", ages["allen"]) // ok
fmt.Printf("wukong: %d\n", ages["wukong"]) // 访问不存在的 key?这也是 ok 的。
  • 遍历这个就不细讲了,前面遇到过 N 次了。如下:
for k, v := range ages {
    fmt.Printf("%s: %d\n", k, v)
}

3. 删除一个 key

使用 go 的内置函数 delete 来删除 key,例如:

delete(ages, "allen") // 即使 "allen" 这个 key 不存在也没关系,这是安全的。

4. 注意事项

  • key 要支持 ==

map 固然好用,但是它的 key 必须是支持 == 比较的。不支持 >< 比较这都没有关系,而且 map 底层算法也不使用大小比较这种规则,它只使用 ==

尽管浮点数也支持 ==,但让浮点类型做 key 的代码绝逼脑袋被门夹了……

  • 不要试图猜测 map 的输出的顺序

就拿第 2 节中的例子来说,遍历 ages 输出的结果的顺序,每次运行的结果可能都不一致,这是 Golang 有意而为之。

  • 不要取某个元素的地址

下面这种做法是无法通过编译的,因为 map 的内存是动态变化的。回忆一下 append 是如何给 slice 分配内存的。

age := &ages["allen"] // error
  • 访问不存在的 key

这一点和其它语言截然不同。Go 里访问一个不存在的 key,不会b出错,仍然会返回 value 对应类型的零 值。在第 2 节里,value 的类型是 int,对应的零值就是 0,因此打印出来的 ages["wukong"] 是 0.

如果是这样,map 如何判断 key 到底存在还是不存在呢?我们不能简单的使用 ages["wukong"] == 0 为真就说 “wukong” 这个 key 不存在。因此,Go 里提供了第二种访问 map 的方法:

age, ok := ages["wukong"]

这种情况下,使用下标 “wukong” 可以返回两个值,第 1 个就是 value 的值,第 2 个值是 boolean 类型,如果为真,表示 key 存在,否则不存在。比如我们希望做到,如果 key 存在就打印输出:

if age, ok := age["wukong"]; ok {
    fmt.Printf("wukong: %d\n", age)
}

5. 总结

  • 掌握声明与定义 map 的方法
  • 注意空 map 的两种情况:1. 有引用,没有元素;2. nil 值
  • 遍历 map —— range 遍历
  • 访问元素 —— 使用下标
  • 判断 key 是否存在 —— 返回两个值

map 这种数据结构的基本使用方法就这些了,实际编程的时候就靠你自己灵活应用了

猜你喜欢

转载自blog.csdn.net/q1007729991/article/details/80159162