写点什么

Go 必知必会:探索 Go 语言中的 map,灵活而强大的键值对集合

作者:王中阳Go
  • 2024-09-07
    北京
  • 本文字数:2311 字

    阅读完需:约 8 分钟

Go必知必会:探索Go语言中的map,灵活而强大的键值对集合

本文来自极客学院专栏,欢迎订阅:Go入门进阶实战专栏:其实学Go很简单。


在 Go 语言的丰富数据结构中,map 以其独特的灵活性和强大的功能脱颖而出,它是 Go 中实现键值对集合的内置类型,允许开发者以一种高效且直观的方式存储和检索数据。从简单的配置管理到复杂的数据索引,在 Go 程序中的应用无处不在。

基础概念

在 Go 中,map 是一个无序的键值对集合,其中键是唯一的。每个键都映射到一个值,并且可以通过键来访问对应的值;与数组和切片不同,map 不是基于索引的数据结构,而是基于键的数据结构。

声明 map

和切片的定义一样,我们定义 map 未进行初始化时,map==nil。map 和切片一样,也是引用类型,不是值类型。


var m1 map[string]int  //声明fmt.Println(m1 == nil) //返回true  
复制代码


没有初始化,说明没有在内存中开辟空间,没有内存地址。

初始化

map 的初始化一定要先声明,再初始化;不能直接初始化,否则会报错:undefined。


var m1 map[string]intm1 = make(map[string]int, 10) //要估算好map的容量,避免在程序运行期间在动态扩容(动态扩容会影响程序运行效率)m1["lucky"] = 18m1["jason"] = 24fmt.Println(m1)
复制代码


打印结果:



注意:要估算好 map 的容量,避免在程序运行期间再动态扩容(动态扩容会影响程序运行效率)。


也可以使用:=简化,代表声明并初始化。


我们把上面的代码简化一下:


//简化 := 表示声明并初始化m1 := make(map[string]int,10)m1["lucky"] = 18m1["jason"] = 24fmt.Println(m1)
复制代码


打印结果:



我们发现结果是一样的。


开发过程中根据场景来判断使用哪种方式来进行声明、初始化操作。

取值

取值非常简单,map[key] 的方式就能取值了,例如:


fmt.Println(m1["jason"])fmt.Println(m1["jason1"]) //map查询不存在的key也不会报错 返回了空值
复制代码


打印结果:



注意:map 查询不存在的 key 不会报错的,返回了空值。

取值判断

上面提到了 map 查询不存在的 key 值也不会报错,而是返回了空值。


如何判断取到的值是否为空值呢?


建议 map 取值的时候这么写:


value,ok := m1["jason1"]if ok {   fmt.Println(value)}else {   fmt.Println("不存在")}
复制代码


打印结果:


遍历取值

取出键值对

for k, v := range m1 {   fmt.Println(k,v)}
复制代码


打印结果:


只取键

for k := range m1 {   fmt.Println(k)}
复制代码


打印结果:


只取值

for _, v := range m1 {   fmt.Println(v)}
复制代码


打印结果:


删除 delete()

map 的删除很简单,内置了 delete 函数;


不像切片移除元素那么复杂,切片移除元素只能通过分割+append 的方式。


var m1 map[string]intm1 = make(map[string]int, 10)m1["lucky"] = 18m1["jason"] = 24fmt.Println(m1)
delete(m1,"jason")fmt.Println(m1)
复制代码


打印结果:



删除不存在的 key,也不会报错。


var m1 map[string]intm1 = make(map[string]int, 10)m1["lucky"] = 18m1["jason"] = 24fmt.Println(m1)fmt.Println("------")delete(m1, "wzy")fmt.Println(m1)
复制代码


打印结果:


排序

map 没有直接排序的内置方法。


下面介绍一种排序思路:我们取出 map 的 key,存储到切片中,对 key 进行排序,再根据排序后的 key 取出 map 中的值。


实现思路如下:


package main
import ( "fmt" "math/rand" "sort" "time")
func main() { // 初始化随机数种子 rand.Seed(time.Now().UnixNano())
// 声明+初始化map var scoreMap = make(map[string]int, 100)
// 填充数据 for i := 0; i < 100; i++ { key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串 value := rand.Intn(100) //生成0~99的随机整数 scoreMap[key] = value //这里的赋值用= 而不是:= } //总结: =是赋值 :=是声明并赋值
// 取出map中所有的key 存到keys切片中 var keys = make([]string, 0, 200) for key := range scoreMap { keys = append(keys, key) }
// 对切片进行排序 sort.Strings(keys) // 按照排序后的keys遍历map for _, key := range keys { fmt.Println(key, scoreMap[key]) }}
复制代码


注意:


  1. 定义变量时,var 和 :=不能同时存在,因为:=代表声明并初始化,同时使用会提示重复声明错误。

  2. Go 生成可变的随机数需要设置随机种子,我们一般将时间戳设置为随机种子:rand.Seed(time.Now().UnixNano())

应用实战

如何生成 map 类型的切片

// 元素为map的切片var s = make([]map[string]int, 1, 10)fmt.Println(s)// 先初始化maps[0] = make(map[string]int, 1)// 赋值s[0]["wzyage"] = 18fmt.Printf("s类型:%T s的值:%v\n",s,s)
复制代码


打印结果:


如何生成切片类型的 map

// 值为切片类型的mapvar m = make(map[string][]int, 1)m["北京"] = []int{1, 2, 3} //声明并初始化了fmt.Printf("m类型:%T m的值:%v", m, m)
复制代码


打印结果:


思考题

有没有办法通过 make()初始化且赋值呢?


经过一番研究之后,发现是不可以的,make()的作用就是初始化为默认值,指定容量。


比如我们改写一下上面生成切片类型map的``例子``:


// 值为切片类型的mapvar m = make(map[string][]int, 1)// 用make初始化切片m["北京"] = make([]int, 3)fmt.Printf("m类型:%T m的值:%v", m, m)
复制代码


打印结果:



总结:只能通过 make()函数初始化(分配内存地址),不能使用 make 直接赋值。

总结

这篇文章汇总了 map 的知识点,包括 map 的声明和初始化、map 的取值、map 的赋值、map 删除元素、map 虽然不能直接排序,但是我们可以通过借助切片保存 key 来排序。


以及如何 map 和切片如何进行搭配使用。


欢迎关注 ❤


我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:【infoQ】。

发布于: 刚刚阅读数: 2
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论

发布
暂无评论
Go必知必会:探索Go语言中的map,灵活而强大的键值对集合_map_王中阳Go_InfoQ写作社区