map实现方式
版本:1.20 源码位置:src/runtime/map.go
数据结构:
type hmap struct {
count int // 当前容量,len(m)返回值
flags uint8
B uint8 // 负载因子
noverflow uint16 // 溢出,用于解决哈希冲突
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}
数据存放都是通过指针偏移方式计算得出
初始化:
func reflect_makemap(t *maptype, cap int) *hmap {
.....
return makemap(t, cap, nil)
}
根据cap初始化B的大小
查找:
根据key计算出哈希值,低位(根据B计算)代表外部所有桶位置,高位代表桶内部的位置
高位相等,对比key
搬迁过程优先从旧buckets中查找
插入:
根据key计算hash
找桶:bucket := hash & bucketMask(h.B); b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize)))
遍历tophash找出桶里面的空位,bucketCnt=8
删除:
查找
找到后删除
重新整理tophash
PS:不会自动缩容
扩容:
负载因子=键数量/bucket数量,什么条件需要rehash
2倍扩容方式,循序渐进赋值
等量扩容
问题:
为什么遍历返回结果是无序,因为startBucket是根据r随机计算得出
// decide where to start
var r uintptr
if h.B > 31-bucketCntBits {
r = uintptr(fastrand64())
} else {
r = uintptr(fastrand())
}
it.startBucket = r & bucketMask(h.B)