哈希表是除了数组之外,最常见的数据结构。Go 语言中的 map 底层就是哈希表,可以很方便地提供键值对的映射。
特性
未初始化的 map 的值为 nil,向值为 nil 的 map 添加元素会触发 panic,这是新手容易犯的错误之一。
map 操作不是原子的,多个协程同时操作 map 时有可能产生读写冲突,此时会触发 panic 导致程序退出。如果需要并发读写,可以使用锁来保护 map,也可以使用标准库 sync 包中的 sync.Map。
实现原理
数据结构
map 的底层数据结构由 runtime/map.go/hmap 定义:
type hmap struct {
count int // 元素个数,调用 len(map) 时,直接返回此值
flags uint8
B uint8 // buckets 数组长度的对数
noverflow uint16 // overflow 的 bucket 近似数
hash0 uint32 // 哈希种子,为哈希函数的结果引入随机性,在调用哈希函数时作为参数传入
buckets unsafe.Pointer // 指向 buckets 数组,大小为 2^B,元素个数为0时为 nil
oldbuckets unsafe.Pointer // 在扩容时用于保存旧 buckets 数组,大小为 buckets 的一半
nevacuate uintptr // 指示扩容进度,小于此地址的 bucke