发布时间:2024-11-22 00:51:57
Golang是一门静态类型、编译型、并发安全的编程语言,拥有丰富的标准库和强大的性能。其中 map 是 Golang 标准库中常用的一种数据结构,下面我们将对 Golang map 的源代码进行解析。
Map 在 Golang 中是以 hash 表的形式实现的。其底层使用了一个 hmap 结构体表示。hmap 在 hashmap.go 中定义。其具体结构如下:
type hmap struct {
count int
flags uint8
B uint8
noverflow uint16
hash0 uint32
buckets unsafe.Pointer
oldbuckets unsafe.Pointer
extra *mapextra
}
其中,count 表示 map 中元素的数量,flags 用于标记其他信息,B 是数组的大小,buckets 存储了实际的 key-value 数据,oldbuckets 用于扩容操作时保存旧的桶结构。
使用 make() 函数可以创建一个新的 map。创建 map 的代码如下:
func make(map[T]T1, hint int) map[T]T1 {
var hmap = new(hmap)
if hint < 0 || hint > maxSliceCap {
hint = maxSliceCap
}
hint = roundUpPowerOf2(hint)
if hint > 0 {
hmap.buckets = newarray(0, uintptr(hint)*bucketSize)
}
hmap.extra = new(mapextra)
return *(*map[T]T1)(unsafe.Pointer(&hmap))
}
该函数会返回一个新创建的 map,hint 参数用于设置 map 的初始容量,如果 hint 值超过了最大容量,则会被设置为最大容量。然后使用 new() 创建一个 hmap 结构体,再根据 hint 值决定是否创建 buckets 数组,最后返回 hmap 类型转换后的 map。
将元素插入 map 中的代码如下:
func mapassign(t *maptype, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer {
h := t.hasher(key, uintptr(hkey))
...
if B == 0 {
addbucket(t, m, h, k, v)
}
...
}
func addbucket(t *maptype, hmap unsafe.Pointer, hash uintptr, key, value unsafe.Pointer) {
...
b := bucketMask(hash, S)
...
}
其中,mapassign 函数根据 key 计算出 hash 值,并通过调用 addbucket() 函数将 key-value 添加到 map 中。addbucket() 函数会根据 hash 值和桶数组的大小计算出应该存放的桶位置,并将 key-value 存储在对应的桶中。
查找 map 中的元素的代码如下:
func mapaccess1(t *maptype, hmap unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer {
...
if B == 0 {
return nil
}
...
b := bucketMask(hash, S)
...
}
其中,mapaccess1 函数根据 key 计算出 hash 值,并根据 hash 值和桶数组的大小计算出应该查找的桶位置。如果桶大小为零,则表示 map 为空,直接返回 nil。如果桶不为空,会继续处理。
从 map 中删除元素的代码如下:
func mapdelete(t *maptype, hmap unsafe.Pointer, key unsafe.Pointer) {
...
if B == 0 {
return
}
...
}
mapdelete 函数也是先判断桶大小是否为零,如果是则表示 map 为空,直接返回。否则继续处理。
遍历 map 中所有元素的代码如下:
func mapiterinit(t *maptype, hmap unsafe.Pointer, it *hiter) {
it.t = t
it.h = hmap
it.B = B
...
}
...
for {
...
y := bucketValHashSudoDone(y, h.B)
if y == bucketNone {
...
break
}
...
}
其中,mapiterinit 函数将 map、map 的类型、map 的大小等信息保存在 hiter 结构体中。然后通过循环遍历桶数组,获取桶中的元素,并进行相应的处理。
以上就是 Golang map 在源代码中的部分实现。map 是 Golang 应用非常广泛的一种数据结构,在项目中使用 map 可以极大地方便开发。了解其底层实现原理可以帮助我们更好地使用 map,并在需要优化性能时进行相关的调整。希望本文对你理解 Golang map 的实现原理有所帮助。