基础及操作
key-value模式
1.声明
var hashMap map[keyType][valueType]
var testMap map[string]string
testMap = make(map[string]string,10)
//直接make
cites := make(map[string]string)
//直接赋值
people := map[string]string{
"people1":"haha",
"people2":"wawa",
}
key的类型
- 1.可以为bool,数字,string,指针,channel,还可以是包含上述类型的借口结构体数组,但通常是int、string;
- 2.slice、map、function不能作为key,因为这几个无法使用==判断
value的类型
- 和key一样,通常是数字(浮点数、整数),string,struct,map
- 声明不分配内存,需要make初始化才能赋值、使用
说明
- key不能重复;value可以
- map无序key value,不根据添加顺序,也不按照key排序
小练习
students := make(map[string]map[string]string)
students["1"] = make(map[string]string,2)
students["1"]["name"] = "tom"
students["1"]["sex"] = "nan"
students["2"] = make(map[string]string,2)
students["2"]["name"] = "mary"
students["2"]["sex"] = "nv"
2.map 操作
增和改 map[key]=value
删除 delete(map,"key")
存在key删除,无也不报错;若想全部删除就遍历删除,或者make一个新空间,让gc处理
查找
value,findRes = people["1"]
if findRes{
return value
}else{
return "cant find it"
}
遍历(只有for range)
不可用for循环:map无序即无下标
for k,v := range maps{
fmt.Printf("k=%v,v=%v",k,v)
}
- 获取长度 len()
len(map)
- 按key排序
- 1.将map的key放入切片中
- 2.对切片排序
- 3.遍历切片,按照key输出值
intSort := make(map[int]int,4)
intSort[10] = 20
intSort[110] = 1
intSort[40] = 5
intSort[90] = 2
var keys []int
for k,_ := range intSort{
keys = append(keys,k)
}
sort.Ints(keys)
for _,k := range keys{
fmt.Printf("map[%v]=%v",k,intSort[k])
}
3 map切片
此处创建了map切片,还有新增map的append
monster := make([]map[string]string,1)
if monster[0] == nil{
monster[0] = make(map[string]string,2)
monster[0]["name"] = "吴亦凡"
monster[0]["age"] = "30"
}
monsterNew := map[string]string{
"name":"a",
"age":"20",
}
monster = append(monster,monsterNew)
使用细节
- 1.引用类型,故函数中会改变其值
- 2.map可以动态增长键值对,即自动扩容
- 3.map的value更适合管理struct
高级
1 数据结构
map 又称为 hash map,在算法上基于 hash 实现 key 的映射和寻址;在数据结构上基于桶数组实现 key-value 对的存储。
以一组 key-value 对写入 map 的流程为例进行简述:
(1)通过哈希方法取得 key 的 hash 值;
(2)hash 值对桶数组长度取模,确定其所属的桶;
(3)在桶中插入 key-value 对。
1.1 hmap
type hmap struct {
count int
flags uint8
B uint8
noverflow uint16
hash0 uint32
buckets unsafe.Pointer
oldbuckets unsafe.Pointer
nevacuate uintptr
extra *mapextra
}
- count:map 中的 key-value 总数;
- flags:map 状态标识,可以标识出 map 是否被 goroutine 并发读写;
- B:桶数组长度的指数,桶数组长度为 2^B;
- noverflow:map 中溢出桶的数量;
- hash0:hash 随机因子,生成 key 的 hash 值时会使用到;
- buckets:桶数组;
- oldbuckets:扩容过程中老的桶数组;
- nevacuate:扩容时的进度标识,index 小于 nevacuate 的桶都已经由老桶转移到新桶中;
- extra:预申请的溢出桶.
1.2 mapextra
type mapextra struct {
overflow *[]*bmap
oldoverflow *[]*bmap
nextOverflow *bmap
}
在 map 初始化时,倘若容量过大,会提前申请好一批溢出桶,以供后续使用,这部分溢出桶存放在 hmap.mapextra 当中:
- mapextra.overflow:供桶数组 buckets 使用的溢出桶;
- mapextra.oldoverFlow: 扩容流程中,供老桶数组 oldBuckets 使用的溢出桶;
- mapextra.nextOverflow:下一个可用的溢出桶.
1.3 bmap
const bucketCnt = 8
type bmap struct {
tophash [bucketCnt]uint8
}
- bmap 就是 map 中的桶,可以存储 8 组 key-value 对的数据,以及一个指向下一个溢出桶的指针;
- 每组 key-value 对数据包含 key 高 8 位 hash 值 tophash,key 和 val 三部分;
- 在代码层面只展示了 tophash 部分,但由于 tophash、key 和 val 的数据长度固定,因此可以通过内存地址偏移的方式寻找到后续的 key 数组、val 数组以及溢出桶指针;
- 为方便理解,把完整的 bmap 类声明代码补充如下:
type bmap struct {
tophash [bucketCnt]uint8
keys [bucketCnt]T
values [bucketCnt]T
overflow uint8
}