golang map源代码

发布时间:2024-07-04 22:27:49

Golang Map 源代码解析

Golang是一门静态类型、编译型、并发安全的编程语言,拥有丰富的标准库和强大的性能。其中 map 是 Golang 标准库中常用的一种数据结构,下面我们将对 Golang map 的源代码进行解析。

1. 数据结构

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 用于扩容操作时保存旧的桶结构。

2. 创建 Map

使用 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。

3. 插入元素

将元素插入 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 存储在对应的桶中。

4. 查找元素

查找 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。如果桶不为空,会继续处理。

5. 删除元素

从 map 中删除元素的代码如下:


func mapdelete(t *maptype, hmap unsafe.Pointer, key unsafe.Pointer) {
    ...
    if B == 0 {
        return
    }
    ...
}

mapdelete 函数也是先判断桶大小是否为零,如果是则表示 map 为空,直接返回。否则继续处理。

6. 遍历 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 的实现原理有所帮助。

相关推荐