一、map基本概念
golang中的map和Python中的字典差不多,它的格式为map[keyType]valueType,是键值对的集合。
二、map基本操作
1.创建
(1)声明再初始化式:var m map[string]string,map的声明的时候默认值是 nil ,此时进行取值,返回的是对应类型的零值,后需要使用m=make(map[string]string)进行初始化
(2)make创建式:m := make(map[string]int)
(3)字面量声明式: m := map[string]int{“age”:18,“sex”:0,}
2.增加&修改&删除&查询&判断是否存在
// 增加
m[“name”] = “云计算小哥”
// 删除,如果key不存在则什么也不做
delete(m, “name”)
// 更新
m[“name”] = “云计算数据库小哥”
// 查询,key不存在返回value类型的零值
v := m[“name”]
// 查询+判断key是否存在
v, ok := m[“name”]
_, ok := m[“name”]
3.遍历
for-range方式
4.map清空
go语言中并没有为 map 提供任何清空所有元素的函数。清空 map 的唯一办法就是重新 make一个新的 map。
三、map的key和value
1.key必须是支持==或!=比较运算的类型,不可以function、map或slice
2.value可以说任意类型,所以其支持嵌套定义即map[string]map[string]string
四、map作为函数参数传递
golang函数参数传递采用的是值传递的方式,但是map本身是引用类型,作为 形参 或返回参数的时候,传递的是地址的拷贝,而且扩容时也不会改变这个地址( 扩容这点和slice差异较大 )
package main
omport “fmt”
m := make(map[string]string, 1)
m[“name”]=“go”
fmt.Printf(“m address:%p\n”, m)
updateMap(m)
fmt.Printf(“after update,m address is:%p\n”, m)
func updateMap(m map[string]string) {
fmt.Printf(“m address in updateMap:%p\n”, m)
m[“age”]=“10”
m[“kind”]=“computer”
fmt.Printf(“m address before updateMap return:%p\n”, m)
}
五、并发map
1.原生的map是非 线程安全
2.如果想使用线程安全的map,可以使用sync.Map或者参考beego的BeegoMap实现,采用锁方式
六、map的gc回收机制
1.map在golang里头是一种只增不减的数组结构,在删除的时候会进行打标记说明该内存空间已经empty了,但不会回收的。
2.如果要回收,需要删除完后,进行设为nil
七、map底层数据结构
type hmap struct {
count int //元素个数
flags uint8
B uint8 //扩容常量
noverflow uint16 //溢出 bucket 个数
hash0 uint32 //hash 种子
buckets unsafe.Pointer //bucket 数组指针
oldbuckets unsafe.Pointer //扩容时旧的buckets 数组指针
nevacuate uintptr //扩容搬迁进度
extra *mapextra //记录溢出相关
}
type bmap struct {
tophash [bucketCnt]uint8
// Followed by bucketCnt keys
//and then bucketan Cnt values
// Followed by overflow pointer.
}
Golang中map的底层实现是一个 散列表 ,因此实现map的过程实际上就是实现散表的过程。在这个散列表中,主要出现的结构体有两个,一个叫hmap(a header for a go map),一个叫bmap(a bucket for a Go map,通常叫其bucket)