字典map

字典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中的元素取地址

联系管理员微信tutu19192010,注册账号

上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术