Go语言复合数据类型之map
文章目录
map的定义
哈希表是一个无序的key/value对的集合,要求所有的key必须不同,然后通过给定的key可以在O(1)内检索、更新或者删除对应的value。
go语言中map就是一个哈希表,其表达形式为map[key] = value ,key在map中是同一种数据类型,其中key必须是支持比较运算符的类型,所以map可以通过测试key是否相等来判断此key是否已经存在。注意,不建议使用float浮点数来作为key,因为最坏的情况可能是出现NaN和任务浮点数都不想等。对于value类型则没有限制。
map的初始化
使用内置make函数初始化
ages := make(map[string]int,len,cap) //len 和cap 可以省略
ages["zhangsan"] = 20
ages["lisi"] = 16
//map[lisi:16 zhangsan:20]
此时key为string 类型,value为int类型。
使用map字面值语法初始化
ages := map[string]int{}
此时创建了一个空的map。
创建指定key/value的map
ages := map[string]int{
"laowang": 22,
"laoli": 25,
}
//map[laoli:25 laowang:22]
此时初始化了一个指定key/value的map。等价于
ages := make(map[string]int)
ages["laowang"] = 22
ages["laoli"] = 25
当声明了map没有进行初始化时,map的值是nil
,长度为0。
var mm map[string]string
fmt.Println(mm == nil) //true
fmt.Println(len(mm)) //0
map的操作
创建一个map
ages := make(map[string]int)
ages["zhangsan"] = 20
ages["lisi"] = 16
//map[lisi:16 zhangsan:20]
map对值的操作
map可以直接根据key获取到对应的值
ages["zhangsan"]++
ages["unknow"]++
fmt.Println(ages["zhangsan"]) //21
fmt.Println(ages["unknow"]) //1
married := make(map[string]bool)
married["zhangsan"] = true
married["lisi"] = false
fmt.Println(married["zhangsan"]) //true
fmt.Println(married["xiaolizi"]) // false
根据键获取值,如果找得到对应的value,则返回,如果找不到则返回其value默认值,因此ages["unknow"]++
此表达式也是合法的,返回值为1。
那么是如何区分key存在的0值和不存在时的0值的,好在go语言的下标语法将返回两个值;第二个是一个布尔值,用来报告元素是否存在,通常命名为ok。具体写法如下
if _, ok := mm["key"]; !ok {
fmt.Println("key is not exist")
}
注:不允许向nil值的map中存入元素,会导致一个panic异常。
var mm map[string]string
mm["zhangsan"] = "haha" //panic: assignment to entry in nil map
map中的元素并不是一个变量,因此不能对map进行取址操作。
_ := &married["zhangsan"] //cannot take the address of married["zhangsan"]
禁止对map进行取址的原因是map可能随着元素数量的增长而重新分配内存空间,从而导致之前的取址操作无效。
使用delete删除key
使用内置的delete函数可以对map的键值对进行删除,如果找不到对应的key,也不会发生panic。
delete(ages, "zhangsan")
fmt.Println(ages) //map[lisi:16]
map的遍历
使用for-range可以对map进行遍历
ages := make(map[string]int)
ages["zhangsan"] = 20
ages["lisi"] = 16
ages["aqi"] = 31
for k, v := range ages {
fmt.Printf("%s %d\n", k, v)
}
//zhangsan 21
//lisi 16
//aqi 31
哈希表是无序的,所以遍历的结果也是无序的,如果需要按顺序便利可以先对key进行排序,然后在遍历。具体实现如下:
var names []string
for name := range ages {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
fmt.Printf("%s %d\n", name, ages[name])
}
//aqi 31
//lisi 16
//zhangsan 21
对map进行遍历,如果不需要值,可以忽略循环的第二个参数。
sort.Strings()函数可以针对string类型的切片进行排序。
在对names 切片进行遍历时,不需要用到索引,可以使用_
空白标志符来占位。
补充
- map的键必须是可比较的,但一些时候想用slice等类型作为key,那么可以借助辅助函数来完成,将slice转换成string等可比较的类型就可以了。
- map中的值并不一定是基础数据类型,比如map的值可以是一个map
mn := make(map[string]map[string]bool)