字典Map
一 Map类型介绍与定义及初始化
Map类型又可以称之为字典类型,是一种无需的基于key:value的数据结构
定义语法如下
map[KeyType]ValueType
//1、KeyType:表示键的类型,
//2、ValueType:表示键对应的值的类型
//3、map中所有的Key都必须是相同的类型,所有的value也必须都是相同的类型,但是key与value之间可以是不同的类型
//4、其中KeyType必须是可以与非nil值进行相等性判断的类型(所有的值类型都支持相等性判断,所有的引用类型只能与nil值判断),因此我们可以通过与key的相等性判断来判定key是否存在。虽然浮点类型也支持与非nil值进行相等性运算,但是不建议用浮点型作为KeyType,因为浮点数存在非数NaN,而NaN与任何浮点数都不相等,这便失去了意义。
//5、对于ValueType没有任何限制
示范
var m map[string]int
fmt.Println(m) // map[]
fmt.Println(m==nil) // true
因为Map与切片类型一样都是引用类型,所以零值为nil,所以无法完成下述赋值
m["k1"]=111 // panic异常: assignment to entry in nil map
·需要我们用make函数为其申请好内存空间
make(map[KeyType]ValueType)
// 示例
var m = make(map[string]int)
fmt.Println(m) // map[]
fmt.Println(m==nil) // false
m["k1"]=111
fmt.Println(m) // map[k1:111]
我们也可以用map字面值的语法创建map,同时还可以指定一些最初的key/value:
scoreMap:=map[string]int{
"egon":99,
"铁蛋":100,
"铜蛋":88,
}
// 上述代码等同于
scoreMap := make(map[string]int)
scoreMap["egon"] = 99
scoreMap["铁蛋"] = 100
scoreMap["铜蛋"] = 88
fmt.Println(scoreMap["egon"]) // 99
我们可以创建一个空的map:表达式是map[string]int{}
var scoreMap = map[string]int{}
fmt.Println(scoreMap == nil) // false
scoreMap["egon"] = 99
fmt.Println(scoreMap["egon"]) // 99
二 map元素的增删改查
var m = make(map[string]string)
// 增加
m["name"]="egon"
m["age"]="18"
m["gender"]="male"
fmt.Println(m) // map[age:18 gender:male name:egon]
// 删除
delete(m,"gender")
fmt.Println(m) // map[age:18 name:egon]
delete(m,"kkk") // 即使key不在map中也没有关系
// 改
m["name"]="Egon"
fmt.Println(m)
// 查
fmt.Println(m["name"]) // Egon
fmt.Println(m["gender"]) // 若key不存在则返回value对应类型的零值
// ps:针对查操作,因为当key不存在时返回的是value对应类型的零值,所以我们可以这么做
var ages = make(map[string]int)
ages["egon"] += 1 // ages["egon"] = ages["egon"] + 1
fmt.Println(ages) // 1
或者
ages["egon"]++
fmt.Println(ages) // 2
三 判断key是否存在于map中
针对操作m[key],当key不存在时,返回的是value对应类型的零值,而极有可能出现key存在,但该key对应的值与其零值是相等的,如下所示
var ages = make(map[string]int)
ages["张三"]=0
fmt.Println(ages["张三"]) // 键"张三"存在,取到值为0
fmt.Println(ages["egon"]) // 键"egon"不存在,取到值对应类型的零值同样为0
所以我们无法通过m[key]取到的值作为判断依据来判定key是否存在,需要这么做
age1,ok:=ages["张三"]
fmt.Println(age1,ok) // 0 true,true代表key存在,0就是取到的值
age2,ok:=ages["egon"]
fmt.Println(age2,ok) // 0 false,false代表key不存在,0是值对应类型的零值
if ok {
fmt.Println(age2)
} else {
fmt.Println("查无此人")
}
四 遍历map
Go语言中使用for range
遍历map
var ages = make(map[string]int)
ages["egon"] = 18
ages["张三"] = 19
ages["李四"] = 20
// 1、循环读取k和v
for k,v := range ages {
fmt.Println(k,v)
}
// 2、循环只读取k,下述两种方式都可以
for k,_ := range ages {
fmt.Println(k,v)
}
for k := range ages {
fmt.Println(k)
}
// 3、循环只读取v
for _,v := range ages {
fmt.Println(v)
}
遍历map时的元素顺序与添加键值对的顺序无关,若想按照指定顺序遍map,需要将map中的key存入切片,然后对切片进行排序后,依据切片中排序好的key依次取map中的value
var ages = make(map[string]int)
ages["egon"] = 18
ages["张三"] = 19
ages["李四"] = 20
ages["王五"] = 21
ages["牛佰"] = 22
// 1、无序遍历
for k, v := range ages {
fmt.Println(k, v)
}
// 2、有序遍历
var keys []string
for k := range ages {
keys = append(keys, k)
}
sort.Strings(keys) // Strings函数接收的参数是切片类型,这也是我们把age中的key放入切片类型中的原因
for _, k := range keys {
fmt.Printf("%s\t%d\n", k, ages[k])
}
// ps:
因为我们一开始就知道keys的最终大小,因此给切片keys分配一个合适的大小将会更有效,如下所示
keys := make([]string, 0, len(ages)) // 容量刚好可以放下map中全部的key:
五 go禁止对map元素取地址
当新增元素时,map也会随着元素数量的增长而重新分配更大的内存空间,从而可能导致之前的地址无效,了解即可。但是有一点需要注意的是go语言设计规定我们可以对切片中的元素取地址,但是我们无法对map中的元素取地址