摘要:今天我们来学习 Golang 中的 另外一种常用的数据类型,通过数据结构和源码来分析 golang 中的 map 是如何实现的。
数据结构
bucketCntBits = 3 bucketCnt = 1 << bucketCntBits // Maximum average load of a bucket that triggers growth is 6.5. // Represent as loadFactorNum/loadFactorDen, to allow integer math. loadFactorNum = 13 loadFactorDen = 2 type hmap struct { count int //哈希表中元素数量 flags uint8 //标志位,每一位有特定的含义,比如写标识 B uint8 //bucket 的数量,len(buckets) = pow(2, B) noverflow uint16 hash0 uint32 //传入 Hash 函数的哈希种子 buckets *bmap //指向 bmap 结构体数组的指针 oldbuckets *bmap //哈希扩容时候用到,和 Redis 哈希扩容策略相同 nevacuate uintptr extra unsafe.Pointer // *mapextra } type bmap struct { topbits [8]uint8 //存储哈希值的高 8 位 keys[8] keytype //存储 8 个 key values[8] valuetype //存储 8 个 value pad uintptr //内存对齐 overflow uintptr //溢出桶指针,能减少扩容频率 } // mapextra holds fields that are not present on all maps. type mapextra struct { // If both key and elem do not contain pointers and are inline, then we mark bucket // type as containing no pointers. This avoids scanning such maps. // However, bmap.overflow is a pointer. In order to keep overflow buckets // alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow. // overflow and oldoverflow are only used if key and elem do not contain pointers. // overflow contains overflow buckets for hmap.buckets. // oldoverflow contains overflow buckets for hmap.oldbuckets. // The indirection allows to store a pointer to the slice in hiter. overflow* [] * bmap oldoverflow* [] * bmap // nextOverflow holds a pointer to a free overflow bucket. nextOverflow* bmap }