本文是《Go专家编程》的阅读笔记
1. map的数据结构
Golang底层使用哈希表实现map,哈希表有多个节点,每个节点就一个bucket(桶),每个bucket可以存储最多8对key-value。
type hmap struct {count int // 哈希表中的元素个数...B int // 当前的负载因子...buckets unsafe.Pointer // 桶数组指针oldbuckets unsafe.Pointer // 扩容前的桶...}
hmap.buckets的长度是2^B
2. bucket的数据结构
const (// Maximum number of key/elem pairs a bucket can hold.bucketCntBits = 3bucketCnt = 1 << bucketCntBits // 8)type bmap struct {tophash [bucketCnt]uint8 // 存储哈希值的高8位// 以下两个属性是虚构的,在bmap结构中不存在data byte[1] // key value数据:key/key/key.../value/value/valueoverflow *bmap // 溢出桶的地址}
每个bucket最多存储bucketCnt=8 个键值对
- tophash是长度为8的uint8数组,哈希值低位相同的键存入当前bucket时会将哈希值的高位存储在该数组中,以方便后续匹配 。
 - data存放的是key-value数据,存放的顺序是key/key/key…/value/value/value,这样存放能够节省字节对齐带来的空间浪费。
 - overflow是溢出桶的地址,据此将溢出桶形成链表。
 
3. 哈希冲突
多个哈希值的低位相同命中同一个桶,桶中的键值对超过8个,只能再创建一个键值对存放溢出桶的地址,Golang就是通过这样的链地址法来解决哈希冲突的。
4. 负载因子
负载因子用于描述哈希冲突的情况:负载因子=键数量/桶数量
 哈希表需要将负载因子控制在合适的大小,超过其阀值需要进行rehash,也即键值对重新组织:  
- 负载因子过小,空间利用率低。
 - 负载因子过大,元素存取效率低。过大表示哈希冲突严重,溢出桶形成的链表很长,在链表中查询位置是较慢的。
 
