返回
Go map 源码逐行拆解
后端
2023-10-10 15:56:25
Go map 是 Go 语言中一种重要的数据结构,用于存储键值对。它是一种无序集合,这意味着元素没有特定的顺序。map 非常高效,因为它使用哈希表来存储键,从而实现 O(1) 的查找时间复杂度。
让我们逐行拆解 Go map 的核心源码,深入了解其底层实现原理。
type hmap struct {
count int // # live cells == size of map. Must be first (ie. before buckets).
flags uint8 // map flags.
B uint8 // number of buckets (B == len(buckets)).
noverflow uint16 // number of overflow buckets; or 0.
buckets []*bmap // array of buckets.
oldbuckets []*bmap // previous bucket array (during map expansion).
nelems int // count of elements in map (for iterating).
hash0 uint32 // hash seed.
}
hmap
是 Go map 的底层实现。它包含以下段:
count
: 活跃元素的数量,即 map 的大小。flags
: map 标志,用于指示 map 的状态和特性。B
: 桶的数量。noverflow
: 溢出桶的数量(如果存在)。buckets
: 存储桶的数组。oldbuckets
: 在 map 扩容期间使用的前一个桶数组。nelems
: map 中元素的数量(用于迭代)。hash0
: 哈希种子,用于哈希函数。
type bmap struct {
tophash uint8 // top-level bucket hash.
overflow *bmap // overflow bucket (if not last).
nelems int
data [128]entry
}
bmap
是 map 中的桶。它包含以下关键字段:
tophash
: 顶级桶哈希值。overflow
: 溢出桶(如果不是最后一个)。nelems
: 桶中元素的数量。data
: 存储键值对的数组。
type entry struct {
key *Key
val *Value
keysize int
valsize int
hash uint32
next *entry
}
entry
是 map 中的键值对条目。它包含以下关键字段:
key
: 键。val
: 值。keysize
: 键的大小。valsize
: 值的大小。hash
: 键的哈希值。next
: 指向下一个条目的指针(如果存在溢出)。
查找操作
查找操作通过哈希函数计算键的哈希值,然后使用哈希值作为索引查找相应的桶。如果桶中存在匹配的键,则返回相应的值。如果桶中不存在匹配的键,则搜索溢出桶(如果有)。
插入操作
插入操作与查找操作类似。如果桶中存在匹配的键,则更新相应的值。如果桶中不存在匹配的键,则将新的键值对添加到桶中。如果桶已满,则创建一个溢出桶并将其添加到桶中。
删除操作
删除操作通过哈希函数计算键的哈希值,然后使用哈希值作为索引查找相应的桶。如果桶中存在匹配的键,则删除相应的键值对。如果桶中不存在匹配的键,则搜索溢出桶(如果有)。
并发安全
Go map 使用读写锁来实现并发安全。当对 map 进行写入操作时,会获取写锁。当对 map 进行读取操作时,会获取读锁。这样可以确保对 map 的并发访问是安全的。
结论
通过逐行拆解 Go map 的核心源码,我们深入了解了其底层实现原理。Go map 使用哈希表和读写锁来提供高效、并发安全的键值对存储。掌握 Go map 的核心知识可以帮助我们编写更高效、更健壮的 Go 程序。