基本操作

  1. package main
  2. import "fmt"
  3. func main() {
  4. aMap := map[string]int{
  5. "one": 1,
  6. "two": 2,
  7. "three": 3,
  8. }
  9. k := "two"
  10. v, ok := aMap[k]
  11. if ok {
  12. fmt.Printf("The element of key %q: %d\n", k, v)
  13. } else {
  14. fmt.Println("Not found!")
  15. }
  16. tMap := make(map[int]string)
  17. tMap[1] = "hh"
  18. tMap[2] = "tt"
  19. tMap[3] = "fff"
  20. fmt.Println("tMap: ", tMap)
  21. }

hash table

  • Go 语言的字典类型其实是一个哈希表(hash table) 的特定实现
  • 而在这个实现中、键和元素最大不同在于,键的类型是受限的、值的类型可以是任意的
  • hash table 最重要的一个过程就是: 映射
  • 哈希表 会先用哈希函数把 key转为 hash值、hash value 通常是一个无符号的整数
  • 一个hash table 会持有一定数量的 bucket、这些bucket也可以叫 哈希桶、这里存储了真正的键值对
  • 只要键值对在hash表中、那么就一定会被找到

映射

  • 把 key转为 hash值, 字典不会独立存储任何键的值、但会独立存储他们的哈希值
  • Go语言 字典的 键类型不能是 函数、字典、切片等类型

为什么 键类型不能是 函数、字典、切片等类型?

  • Go 语言规范规定、在键类型的值之间 必须可以施加 == 和 !=
  • 也就是说 Go语言 map 键类型必须要支持 判等操作,所以字典的键类型不能是这些类型
  • 如果 键的类型是接口类型的,那么键值的实际类型也不能是 这三种类型、否则会panic
  1. var badMap2 = map[interface{}]int{
  2. "1": 1,
  3. []int{2}: 2, // 这里会引发panic。语法层面可以、运行时不行
  4. 3: 3,
  5. }

应该优先考虑哪些类型作为 map的 key类型?

  • 性能上来说 把键值转换为 hash值 和 查找的键值与哈希桶中的键值作对比、这两个操作耗时
  • 因此、求哈希 和 判等操作速度越快、对应的类型就越适合作为键类型
  • 宽度越小的类型 求hash的操作就越快、这里宽度指的是单个值需要占的字节数。
  • bool、int8、uint8 类型都是占用一个字节

一个map是nil、对它进行读操作会成功、写操作会成功吗?

  • 由于字典是引用类型、所以当我们仅声明而不初始化字典时、它的值是nil
  • 对一个为nil的字典进行 写操作的时候 会引起运行时 panic
  • 除了添加操作、其他操作都不会失败

map 并发安全吗?

  • 不安全、会引起运行时 panic

源码解析

图解