介绍
- 引用类型
- Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索value。
- key 类似于索引,指向数据的值,key必须可以使用==运算符来比较,不能重复。
- Map 是使用 hash 表来实现的。
- map自动扩容
声明
方式1
var map 变量名 map[key_type]value_type
代码
var m map[string]string
方式2
make函数
func make(Type, size IntegerType) Type
内建函数make分配并初始化一个类型为切片、映射、或通道的对象。其第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针。其具体结果取决于具体的类型:
映射:初始分配的创建取决于size,但产生的映射长度为0。size可以省略,这种情况下就会分配一个小的起始大小。
map的键必须是可以通过操作符==
来比较的数据类型。int、布尔、string、或包含前面的struct、数组等
声明时直接make
var 变量名 = make(map[key_type][value_type])
代码
var m1 = make(map[string]string,5)
初始化
key:value形式,添加到花括号中。
代码
m2 := map[string]string{"野王":"赵云"}
添加/修改
map[key] = value形式,没有会添加,有了会覆盖。
代码
1. m1["上官"] = "言为心声" 2. m1["婉儿"] = "字为心画" 3. m2["野王"] = "老虎" 4. m2["上单"] = "吕布"
删除
func delete(m map[Type]Type1, key Type)
内建函数delete按照指定的键将元素从映射中删除。若m为nil或无此元素,delete不进行操作。
delete(m1,"上官")
清空:重新make,没有其他语言类似clear的函数
查找
m[key]返回值和是否存在(bool类型)
val,flag := m2["野王"] if flag{ fmt.Println("野王:",val) }
内存
查看源码
src->runtime->map.go
// A header for a Go map. type hmap struct { // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/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 }
// A bucket for a Go map. type bmap struct { // tophash generally contains the top byte of the hash value // for each key in this bucket. If tophash[0] < minTopHash, // tophash[0] is a bucket evacuation state instead. tophash [bucketCnt]uint8 // Followed by bucketCnt keys and then bucketCnt elems. // NOTE: packing all the keys together and then all the elems together makes the // code a bit more complicated than alternating key/elem/key/elem/... but it allows // us to eliminate padding which would be needed for, e.g., map[int64]int8. // Followed by an overflow pointer. }
是哈希表实现,拉链法解决冲突。
遍历
for range
for key,value := range m2{ fmt.Println(key,value) }
注意:由于是无序的,go的设计者将遍历做了随机化处理,可就是说两次遍历的结果很可能不一样。
排序
对key排序,然后遍历
m2["野王2"] = "赵云" m2["野王3"] = "玛玛哈哈" m2["上单2"] = "马超" keys := []string{} for key,_ := range m2{ keys = append(keys, key) } sort.Strings(keys) fmt.Println("上单和野王排行榜:") for _,key := range keys{ fmt.Println(key,m2[key]) }
注意:不是线程安全的,如果需要线程安全的,可以使用sync/Map,等到包的那一节会详细展开。
相等
和slice一样,map之间不能使用==直接比较,map可以和nil使用==比较,我们可以使用循环来判断。
ok := func(m1,m2 map[string]string) bool{ if len(m1) != len(m2){ return false } for k,v := range m1{ if v2,ok := m2[k]; !ok || v!=v2{ return false } } return true } (m1,m2) fmt.Println("m1和m2相等?",ok)
全部代码
package main import ( "fmt" "sort" ) func main() { //-------------声明--------------- var m map[string]string //----------声明并分配空间------ var m1 = make(map[string]string,5) m2 := map[string]string{"野王":"赵云"} //---------添加和修改--------------- m1["上官"] = "言为心声" m1["婉儿"] = "字为心画" m2["野王"] = "老虎" m2["上单"] = "吕布" fmt.Println("m m1 m2:",m,m1,m2) //----------删除------------------- delete(m1,"上官") fmt.Println("m1:",m1) //------------查找------------- val,flag := m2["野王"] if flag{ fmt.Println("野王:",val) } //------------遍历------------- for key,value := range m2{ fmt.Println(key,value) } //------------排序------------ m2["野王2"] = "赵云" m2["野王3"] = "玛玛哈哈" m2["上单2"] = "马超" keys := []string{} for key,_ := range m2{ keys = append(keys, key) } sort.Strings(keys) fmt.Println("上单和野王排行榜:") for _,key := range keys{ fmt.Println(key,m2[key]) } }
截图
注意
- key必须可以使用==比较,所以,数组是可以作为key的,但切片不行,类似于Python中的tuple和list
- 向map存数据前需要make或初始化,仅使用var声明的是不行的,仅声明的话,那是nil
参考
更多Go相关内容:Go-Golang学习总结笔记
有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。