【Golang】Go语言Map详解

【Golang】Go语言Map详解,第1张

文章目录 环境大纲一、map基础知识map特点map初始化map访问 二、golang实现1.数据结构2. 访问2.扩容(TODO) 总结(TODO)参考资料


环境

go1.17.8 darwin/arm64

大纲 map特点map基本用法hash table 相关知识 一、map基础知识 map特点 map是哈希表的引用map需要初始化后使用由于map是引用类型,所以传递的成本很低,64位机器上占8字节,32位机器上占4字节map的key的类型必须是可使用==和!=比较的map的中存储的元素是无序的 map初始化 使用字面量,初始化并赋值
m := map[int]string{
	1:"one",
	2:"two",
}
使用make关键字
m := make(map[int]string)
m[1]="one"
m[2]="two"
map访问 遍历
m := map[int]string{
	1:"one",
	2:"two",
}

for k,v := range m{
	fmt.Println(k,v)
}
查找key对应的value
m := map[int]string{
	1:"one",
	2:"two",
}

v1 := m[1]
v2 := m[2]

如果map中对应的key不存在,则返回零值。或者判断key是否存在:

m := map[int]string{
	1:"one",
	2:"two",
}

if v1, ok := m[1]; !ok {
	fmt.Println("key 1 is not exist")
}
删除key
m := map[int]string{
	1:"one",
	2:"two",
}

delete(m, 1)
二、golang实现 go使用拉链法解决hash碰撞问题。扩容时不会立马迁移和释放原有空间,而是通过后续的访问逐步的将旧空间中的内容迁移到新空间,再由GC释放旧空间。 1.数据结构


hmap相当于map指向hash表的头指针:


// A header for a Go map.
type hmap struct {
	// Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go.
	// Make sure this stays in sync with the compiler's definition.
	count     int // # live cells == size of map.  Must be first (used by len() builtin)
	flags     uint8
	B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
	noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
	hash0     uint32 // hash seed

	buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

	extra *mapextra // optional fields
}
count:map中的现有元素总数flags:缓存hash表的状态变量B:表示bucket的数量,bucket数量=2^Bnoverflow:计算溢出桶的数量hash0: hash函数的随机数种子,为hash函数添加随机性,map创建时确定buckets: 指向当前桶数组的第一个元素(桶数组的头指针)oldbuckets: 指向旧桶数组的第一个元素extra:指向溢出桶
// A bucket for a Go map.
type bmap struct {
	tophash [bucketCnt]uint8
}

// compile internal struct
type bmap struct {
    tophash  [8]uint8
    keys     [8]keytype
    values   [8]valuetype
    pad      uintptr
    overflow uintptr
}
tophash:存储计算出的hash的高8位值 2. 访问

当一个键值对需要插入或者访问时,首先要根据key键找到存储键的桶,在从桶中查找出相应槽位的key和value。这就涉及到如下三个问题:

如何确定是哪个buckettophash怎么确定为什么key和value通过地址偏移量访问

golang中通过对key哈希后,取hash(key)的低B位来确定bucket的数组下标。通过hash(key)的高8位来与桶中槽位的tophash相比较从而确定应该存储或访问哪个槽位的数据。由于key和value是集中存储的(所有的key存一块儿,value存一块儿,有利于内存对齐),所以很容易通过地址的偏移量方位内存中相应的数据。图示如下:

2.扩容(TODO)
总结(TODO) 参考资料

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/996383.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存