map本质上是一个桶数组,一个桶最多存储 8 个键值对,一个健通过哈希函数,可以固定的映射到一个桶中,然后在桶内通过遍历 8 个健的 方式来寻找正确的键值对位置。如果 有 多于 8 个元素映射到一个桶,则需要分配一个溢出桶来存储,每个桶都保留一个指针,用来指向溢出桶(开放地址寻址法)。
计算哈希值,需要两个输入,一个是哈希函数,一个是哈希种子。
在golang中,哈希函数是固定的,string类型的key,对应哈希函数是hashstr。
哈希种子 hash0 在创建时生成,在整个map存活区间,一般不会变。
但是有个特例,当 删除map 的key,且删除到key 的数量为0 时,会重新生成要给 hash0.
正常桶的个数 = 2的B次方。
扩容
hash map 有个负载因子的概念: 负载因子 = count(元素个数) / 2^B(桶的个数)
情况1: 当负载因子 > 6.5 的 时候,就进行翻倍扩容;
扩容规则
map扩容时使用渐进式扩容。
由于 map 扩容需要将原有的 key/value 重新搬迁到新的内存地址,如果map存储了数以亿计的key-value,一次性搬迁将会造成比较大的延时,因此 Go map 的扩容采取了一种称为**“渐进式”的方式,原有的 key 并不会一次性搬迁完毕,每次最多只会搬迁 2 个 bucket。只有在插入或修改、删除 key 的时候,都会尝试进行搬迁 buckets 的工作**。先检查 oldbuckets 是否搬迁完毕,具体来说就是检查 oldbuckets 是否为 nil。
var map 变量名 map[keytype]valuetype
key 可以是什么类型 :golang 中的 map,的 key 可以是很多种类型,比如 bool, 数字,string, 指针, channel , 还可以是只 包含前面几个类型的 接口, 结构体, 数组
通常 key 为 int 、string 注意: slice, map 还有 function 不可以,因为这几个没法用 == 来判断,不是可比较类型
valuetype 可以是什么类型: valuetype 的类型和 key 基本一样,这里我就不再赘述了 通常为: 数字(整数,浮点数),string,map,struct
网友评论