【Golang第7章:map】go语言中map的基本介绍,golang中map的使用案例,go语言中map的增删改查操作,go语言对map的值进行排序
介绍
这个是在B站上看边看视频边做的笔记,这一章是编程语言go语言的map部分
有go语言中map的基本介绍,golang中map的使用案例,go语言中map的增删改查操作,go语言对map的值进行排序,具体请看【文章目录】
配套视频自己去B站里面搜【go语言】,最高的播放量就是
里面的注释我写的可能不太对,欢迎大佬们指出╰(°▽°)╯
文章目录
(七)、map
一、map 的基本介绍
是key-value 数据结构,又称为字段或者关联数组。类似其它编程语言的集合,在编程中是经常使用到
二、map 的声明
1.基本语法
var map 变量名map[keytype]valuetype
-
key 可以是什么类型
golang 中的map,的key 可以是很多种类型,比如bool, 数字,string, 指针, channel , 还可以是只包含前面几个类型的接口, 结构体, 数组
key
通常为int
、string
注意: slice, map 还有function 不可以,因为这几个没法用== 来判断
-
valuetype 可以是什么类型
valuetype 的类型和key 基本一样
通常为:
数字(整数,浮点数)
,string
,map
,struct
2.map 声明的举例
-
map 声明的举例:
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string
**注意:**声明是不会分配内存的,初始化需要make ,分配内存后才能赋值和使用。
-
案例演示:
func main() { //map的声明和注意事项 var a map[string]string /* a["no1"] = "宋江" //由于只声明了一个空map,没有给予他一个空间,所以出现报错给一个空map赋值报错 fmt.Println(a) */ //在使用map前,需要先make,make的作用是给map分配数据空间 a = make(map[string]string, 10) a["no1"] = "宋江" a["no2"] = "吴用" a["no1"] = "武松" a["no3"] = "吴用" fmt.Println(a) //map[no1:武松 no2:吴用 no3:吴用] }
-
对上面代码说明:
- map 在使用前一定要make
- map 的key 是不能重复,如果重复了,则以最后这个key-value 为准
- map 的value 是可以相同的.
- map 的key-value 是无序
- make 内置函数数目
3.map 的使用
func main() {
//方式1
var a = make(map[string]string, 10)
a["no1"] = "宋江"
a["no2"] = "吴用"
a["no1"] = "武松"
a["no3"] = "吴用"
fmt.Println(a) //map[no1:武松 no2:吴用 no3:吴用]
//方式2
ctiies := make(map[string]string)
ctiies["no1"] = "北京"
ctiies["no2"] = "上海"
ctiies["no3"] = "广州"
fmt.Println(ctiies)
//方式3
heroes := map[string]string{"hero1": "宋江", "hero2": "武松"}
heroes["hero3"] = "林冲"
fmt.Println(heroes)
}
-
map使用案例
练习:演示一个
key-value
的value
是map
的案例比如:我们要存放3 个学生信息, 每个学生有name 和sex 信息
思路:
map[string]map[string]string
代码:
//案例 /* 演示一个key-value 的value 是map 的案例 比如:我们要存放3 个学生信息, 每个学生有name 和sex 信息 思路: map[string]map[string]string */ studentMap := make(map[string]map[string]string) //map嵌套,make第一个map studentMap["stu01"] = make(map[string]string) //make第二个map studentMap["stu01"]["name"] = "Tom" //嵌套赋值 studentMap["stu01"]["sex"] = "男" studentMap["stu01"]["address"] = "北京" studentMap["stu02"] = make(map[string]string) //make第二个map studentMap["stu02"]["name"] = "Mary" studentMap["stu02"]["sex"] = "女" studentMap["stu02"]["address"] = "上海" fmt.Println(studentMap) //查看整个map值 fmt.Println(studentMap["stu02"]) //查看map指定的key fmt.Println(studentMap["stu02"]["name"]) //查看嵌套map内指定的值
4.map的增删改查操作
-
map 增加和更新:
map["key"] = value
//如果key 还没有,就是增加,如果key 存在就是修改。ctiies := make(map[string]string) ctiies["no1"] = "北京" ctiies["no2"] = "上海" ctiies["no3"] = "广州" fmt.Println(ctiies) //因为no3这个key已经存在,因此下面的这句话就是修改 ctiies["no3"] = "上海~" fmt.Println(ctiies)
-
map 查找:
案例演示:
//演示map的查找 val, ok := ctiies["no1"] if ok { fmt.Printf("有no1 key ,值为%v\n", val) } else { fmt.Println("没有no1 key") }
对上面代码的说明:
说明:如果heroes 这个map 中存在"no1" , 那么findRes 就会返回true,否则返回false
-
map 删除:
说明:
delete(map,"key")
,delete
是一个内置函数,如果key 存在,就删除该key-value,如果key 不存在,不操作,但是也不会报错[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qlkh2K04-1669361145534)(assets/image-20221013142404245.png)]
代码:
//演示删除 delete(ctiies, "no1") fmt.Println(ctiies) delete(ctiies, "no4") fmt.Println(ctiies)
-
细节说明:
1.如果我们要删除map 的所有key ,没有一个专门的方法一次删除,可以遍历一下key, 逐个删除
2.或者
map = make(...)
,make 一个新的,让原来的成为垃圾,被gc 回收代码:
//如果希望一次性删除所有的key //1.遍历所有的key,如何逐一删除 [遍历] //2.直接make-个新的空间 cities := make(map[string]string) fmt.Println(cities) //map[]
5.map 遍历和长度
案例演示相对复杂的map 遍历:该map 的value 又是一个map
说明:map 的遍历使用for-range 的结构遍历
-
案例演示:
func main() { //使用for-range遍历map ctiies := make(map[string]string) ctiies["no1"] = "北京" ctiies["no2"] = "上海" ctiies["no3"] = "广州" for k, v := range ctiies { fmt.Printf("k=%v v=%v\n", k, v) } //使用for -range遍历一个结构比较复杂的map studentMap := make(map[string]map[string]string) //map嵌套,make第一个map studentMap["stu01"] = make(map[string]string) //make第二个map studentMap["stu01"]["name"] = "Tom" //嵌套赋值 studentMap["stu01"]["sex"] = "男" studentMap["stu01"]["address"] = "北京" studentMap["stu02"] = make(map[string]string) //make第二个map studentMap["stu02"]["name"] = "Mary" studentMap["stu02"]["sex"] = "女" studentMap["stu02"]["address"] = "上海" for k1, v1 := range studentMap { //先获取第一个map的key fmt.Printf("k1=%v\n", k1) for k2, v2 := range v1 { //使用第一个map的key进行循环,获取第二个map的key fmt.Printf("\tk2=%v v2=%v\n", k2, v2) } } }
- map的长度
6.map 切片
1)基本介绍
切片的数据类型如果是map
,则我们称为slice of map,map
切片,这样使用则map
个数就可以动
态变化了。
2)案例演示
**要求:**使用一个map 来记录monster 的信息name 和age, 也就是说一个monster 对应一个map,并
且妖怪的个数可以动态的增加=>map 切片
func main() {
//演示map切片的使用
/*
要求:使用一个map 来记录monster 的信息name 和age, 也就是说一个monster 对应一个map,并
且妖怪的个数可以动态的增加=>map 切片
*/
var monsters []map[string]string //声明一个map切片
monsters = make([]map[string]string, 2) //对map进行make,生成2个map空间
if monsters[0] == nil {
monsters[0] = make(map[string]string, 2) //对第1个map空间的第进行初始化,能放2个值
monsters[0]["name"] = "牛魔王"
monsters[0]["age"] = "500"
}
if monsters[1] == nil {
monsters[1] = make(map[string]string, 2) //对第2个map空间的第进行初始化,能放2个值
monsters[1]["name"] = "红孩儿"
monsters[1]["age"] = "400"
}
fmt.Println(monsters) //[map[age:500 name:牛魔王] map[age:400 name:红孩儿]]
//这里我们需要使用到切片的append函数,可以动态的增加monster
//1.先定义个monster信息
newMonster := map[string]string{"name": "哥布林", "age": "50"} //直接定义一个map并赋值
newMonster1 := map[string]string{"name": "黑龙", "age": "200", "sex": "123"} //直接定义一个map并赋值
monsters = append(monsters, newMonster, newMonster1) //内建函数append将元素追加到切片的末尾
fmt.Println(monsters) //[map[age:500 name:牛魔王] map[age:400 name:红孩儿] map[age:50 name:哥布林] map[age:200 name:黑龙 sex:123]]
}
7.map 排序
1)基本介绍
- golang 中没有一个专门的方法针对map 的key 进行排序
- golang 中的map 默认是无序的,注意也不是按照添加的顺序存放的,你每次遍历,得到的输出可能不一样. 【案例演示1】
- golang 中map 的排序,是先将key 进行排序,然后根据key 值遍历输出即可
2)演示案例
package main
import (
"fmt"
"sort"
)
func main() {
//map的排序
map1 := make(map[int]int)
map1[10] = 100
map1[1] = 13
map1[4] = 56
map1[8] = 90
fmt.Println(map1)
for k, v := range map1 { //查看是否是无序的
fmt.Printf("key:%v\tvalue:%v\n", k, v) //每次输出的顺序不一样
}
//如果按照map的key的顺序进行排序输出
//1.先将map的key 放入到切片中
//2.对切片排序
//3.遍历切片,然后按照key来输出map的值
var keys []int
for k, _ := range map1 {
keys = append(keys, k) //使用append递增获取所有的key
}
//对key进行排序
fmt.Println(keys)
sort.Ints(keys) //将值按递增的顺序排列
fmt.Println(keys)
for _, k := range keys { //按排列好的大小来获取去map1的值
fmt.Printf("map1[%v]=%v\n", k, map1[k])
}
}
8.map 使用细节
-
map 是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map
-
map 的容量达到后,再想map 增加元素,会自动扩容,并不会发生panic,也就是说map 能动态的增长键值对(key-value)
package main import "fmt" func modify(map1 map[int]int) { map1[10] = 900 } func main() { //map是引用类型,遵守引用类型传递的机制,在一个函数接收map, //修改后,会直接修改原来的map map1 := make(map[int]int, 2) //默认给的容量是2 ,但是没有报错,而且申明的4个都输出了 map1[1] = 90 map1[2] = 88 map1[10] = 1 map1[20] = 2 fmt.Println(map1) //map[1:90 2:88 10:1 20:2] modify(map1) fmt.Println(map1) //map[1:90 2:88 10:900 20:2] 说明map是引用类型 }
-
map 的
value
也经常使用struct 类型,更适合管理复杂的数据(比前面value 是一个map 更好),比如value为Student 结构体【案例演示,因为还没有学结构体,体验一下即可】package main import "fmt" //声明一个学生的结构体 type Stu struct { Name string Age int Address string } func main() { //map的value也经常使用struct类型, //更适合管理复杂的数据(比前面value是一一 个map更好), //比如value为student结构体[ 案例演示,因为还没有学结构体,体验一下即可] //1.map 的key 为学生的学号,是唯一的 //2.map的value为结构体,包含学生的名字,年龄,地址 students := make(map[string]Stu, 10) //make分配空间并设定类型 //创建2个学生 stu1 := Stu{"tom", 18, "北京"} //学生1的信息 stu2 := Stu{"mary", 28, "上海"} //学生2的信息 students["no1"] = stu1 students["no2"] = stu2 fmt.Println(students) //遍历各个学生的信息 for k, v := range students { //获取key值和结构体 fmt.Printf("学生的编号是%v", k) fmt.Printf("学生的名字是%v", v.Name) //获取结构体的值 fmt.Printf("学生的年龄是%v", v.Age) fmt.Printf("学生的地址是%v", v.Address) fmt.Println() } }
9.map 的练习题
-
课堂练习:
- 使用
map[string]map[string]string
的map 类型 - key: 表示用户名,是唯一的,不可以重复
- 如果某个用户名存在,就将其密码修改"888888",如果不存在就增加这个用户信息,(包括昵称nickname 和密码pwd)。
- 编写一个函数
modifyUser(users map[string]map[string]string, name string)
完成上述功能
- 使用
-
代码
package main import "fmt" //1) 使用map[string]map[string]string 的map 类型 //2) key: 表示用户名,是唯一的,不可以重复 //3) 如果某个用户名存在,就将其密码修改"888888",如果不存在就增加这个用户信息,(包括昵称nickname 和密码pwd)。 //4) 编写一个函数modifyUser(users map[string]map[string]string, name string) 完成上述功能 func modifyUser(users map[string]map[string]string, name string) { //声明users的map和声明name的类型 //判断users中是否有这个name if users[name] != nil { //有这个用户 users[name]["passwd"] = "888888" //修改这个用户的密码为888888 } else { //没有这个用户 users[name] = make(map[string]string, 2) //make 一个空间,声明vlue的空间和默认参数 users[name]["passwd"] = "888888" users[name]["nickname"] = "昵称" + name } } func main() { users := make(map[string]map[string]string, 10) users["smith"] = make(map[string]string, 2) //声明Smith密码和昵称 users["smith"]["passwd"] = "999999" users["smith"]["nickname"] = "我是史密斯" fmt.Println(users) modifyUser(users, "tom") //传入参数,没有的名称就添加,有的就修改密码 modifyUser(users, "mary") modifyUser(users, "smith") fmt.Println(users) }
章节目录
【Golang第1~3章:基础】如何安装golang、第一个GO程序、golang的基础
【Golang第4章:函数】Golang包的引用,return语句、指针、匿名函数、闭包、go函数参数传递方式,golang获取当前时间
【Golang第5章:数组与切片】golang如何使用数组、数组的遍历和、使用细节和内存中的布局;golang如何使用切片,切片在内存中的布局
【Golang第6章:排序和查找】golang怎么排序,golang的顺序查找和二分查找,go语言中顺序查找二分查找介绍和案例
【Golang第7章:map】go语言中map的基本介绍,golang中map的使用案例,go语言中map的增删改查操作,go语言对map的值进行排序
【Golang第8章:面向对象编程】Go语言的结构体是什么,怎么声明;Golang方法的调用和声明;go语言面向对象实例,go语言工厂模式;golang面向对象的三大特性:继承、封装、多态
【Golang第9章:项目练习】go项目练习家庭收支记账软件项目、go项目练习客户管理系统项目
【Golang第10章:文件操作】GO语言的文件管理,go语言读文件和写文件、GO语言拷贝文件、GO语言判断文件是否存在、GO语言Json文件格式和解析
【Golang第12章:goroutine协程与channel管道】GO语言goroutine协程和channel管道的基本介绍、goroutine协