Golang中map
官方定义为映射。
基本介绍
map
是key-value
数据结构,一种键值对形式的集合,又称为字段或者关联数组。类似其它编程语言的集合,在编程中经常使用到。
基本语法
var m变量名 map[关键字类型type] 指定值类型type
key
的类型: golang中map
的key
具有多种类型,比如bool、数值、string、指针、管道channel,还可以是包含前面几个类型的接口,结构体、数组。通常为int、string类型。注意:slice,map,function不可以作为key
,因为这几个类型不能使用==
进行判断。
value
的类型: 与key
的类型基本一样,多了map
类型,通常为: 数字(整数、浮点数)、string、map、struct。
map声明举例:
var a map[string]string //key类型string value类型 string
var a map[string]int
var a map[int]string
var a map[int]map[string]int// key类型int value类型map[string]int
//map可以包含多重map
注意:
1.map
声明是不会分配内存的,初始化需要make
,分配内存后才能赋值和使用。(slice
也是如此)
2.map
的键值key
是不可以重复的,值value
是可以重复。
3.key
所对应的value
值是可以修改的
4.map
中的key-value
是无序的
func main() {
//map的声明和注意事项
var a map[string]string
//在使用map必须使用make,给map分配数据空间
fmt.Println(a) // nil map[]
a = make(map[string]string, 10)
//map 赋值操作
a["no.1"] = "宋江"
a["no.2"] = "吴用"
fmt.Println(a) //map[no.1:宋江 no.2:吴用]
//关键字不可重复
a["no.1"] = "武松"
fmt.Println(a) //map[no.1:武松 no.2:吴用]
//value 可以相同
a["no.3"] = "吴用"
fmt.Println(a) //map[no.1:武松 no.2:吴用 no.3:吴用]
a["no.4"] = "鲁智深"
a["no.5"] = "晁盖"
a["no.6"] = "孙二娘"
//Golang的map的key-value 是遍历是无序的
for i, v := range a {
fmt.Printf("%v元素是%v\n", i, v)
}
/*
no.2元素是吴用
no.3元素是吴用
no.1元素是武松
no.4元素是鲁智深
no.5元素是晁盖
no.6元素是孙二娘*/
}
map的使用方式:
var a map[string]string
//在使用map必须使用make,给map分配数据空间
a = make(map[string]string, 10)
//map 赋值操作
a["no.1"] = "宋江"
a["no.2"] = "吴用"
fmt.Println(a) //map[no.1:宋江 no.2:吴用]
//第二种方式 类型推导
cite := make(map[string]string, 10)
cite["no.1"] = "北京"
cite["no.2"] = "南京"
cite["no.2"] = "武汉"
fmt.Println(cite) //map[no.1:北京 no.2:武汉]
//第三种形式 类型推导 +直接使用
hero := map[string]string{
"hero1": "武松",
"hero2": "卢俊义", // 最后一行也必须有“,”
}
fmt.Println(hero) //map[hero1:武松 hero2:卢俊义]
使用案例
要求:
演示一个 key-value 的valeu是map类型的案例
要求:存放三个学生的信息,每个学生有学号 、name 和sex等信息
studentMap := make(map[string]map[string]string)
//value是map类型的,还需进行make,才能使其分配空间,进行赋值操作
studentMap["01234"] = make(map[string]string, 3)
studentMap["01234"]["name"] = "tom"
studentMap["01234"]["sex"] = "male"
studentMap["01234"]["address"] = "武汉天地~"
studentMap["01235"] = make(map[string]string, 3)
studentMap["01235"]["name"] = "marry"
studentMap["01235"]["sex"] = "female"
studentMap["01235"]["address"] = "武汉天地~"
studentMap["01236"] = make(map[string]string, 3)
studentMap["01236"]["name"] = "Jay"
studentMap["01236"]["sex"] = "male"
studentMap["01236"]["address"] = "武汉天地~"
fmt.Println(studentMap)
fmt.Println(studentMap["01234"]) //map[address:武汉天地~ name:tom sex:male]
fmt.Println(studentMap["01234"]["name"]) //tom
map的增删改查操作
1.map的增加和更新:
map["key"] = vlaue
,如果key
不存在,就是增加操作;如果key
存在,就是修改操作。
cite := make(map[string]string, 10)
cite["no.1"] = "北京" //如果没有no.1这个key,就是增加
cite["no.2"] = "南京" //如果没有no.2这个key,就是增加
fmt.Println(cite) //map[no.1:北京 no.2:南京]
cite["no.2"] = "武汉" //如果有no.2这个key,就是修改
fmt.Println(cite) //map[no.1:北京 no.2:武汉]
}
2.map的删除:
使用内嵌函数delete
,delete(map,"key")
,如果key
存在,就删除该key-value
关联数组;如果key
不存在,则不进行删除操作,但也不会报错。
//演示删除
delete(cite, "no.1")
fmt.Println(cite) // map[no.2:武汉]
//当delete指定的key不存在时,不进行删除操作,但也不会报错
delete(cite, "no.4")
fmt.Println(cite) // map[no.2:武汉]
map删除细节说明:
1)想要删除map中的所有key,在Golang中没有一个专门的方法实现一次性删除,可以遍历一下key,逐个删除
2)使用map = make(...)
,make一个新的,让原来的成为垃圾,被gc回收。
// 一次性删除所有的key
// 1.遍历所有的key,逐一删除
heroname := map[string]string{
"hero1": "武松",
"hero2": "九纹龙",
"hero3": "黑旋风",
}
fmt.Println(heroname) //map[hero1:武松 hero2:九纹龙 hero3:黑旋风]
for k,_:= range heroname { //map的遍历支持遍历key,也可写成 k:= range heroname
delete(heroname, k)
}
fmt.Println(heroname) //map[]
//2.直接make一个新空间
heroname1 := map[string]string{
"hero1": "武松",
"hero2": "九纹龙",
}
fmt.Println(heroname1) //map[hero1:武松 hero2:九纹龙]
heroname1 = make(map[string]string)
fmt.Println(heroname1) //map[]
map
映射中查找是否含有某个key
键值,使用val,judge := m[key1]
,其中变量val
类型与m
映射的值类型相同,judge
类型为bool
类型。m
中含有key1
键值,则val = m[key1]
即将m映射中key1键对应的值赋给变量val,并且此时变量judge为true
;若映射m
中不含有key1
键值,则此时变量judge为false
。案例演示:
movieName := make(map[string]string)
movieName["American"] = "Revenger"
movieName["Chinese"] = "满城尽带黄金甲"
//map的查找
// 如果movieName映射中存在key"Chinese",则把key"Chinese"对应的值赋给val,给judge赋值为true
//否则judge 为 false
val, judeg := movieName["Chinese"]
if judeg {
fmt.Printf("movieName映射中含义key:Chinese,对应的值为%v", val)
} else {
fmt.Println("movieName映射中不含义key:Chinese")
}
}
Output:
movieName映射中含义key:Chinese,对应的值为满城尽带黄金甲
map遍历
map
的遍历使用for-range
结构遍历;当map
的value
是map
类型时,使用多重for-range
结构遍历。
案例演示:
ctiesName := make(map[string]map[string]string)
ctiesName["武汉"] = map[string]string{
"省份": "湖北",
"车牌": "鄂A",
"景点": "黄鹤.楼....",
}
ctiesName["北京"] = make(map[string]string)
ctiesName["北京"]["省份"] = "直辖市"
ctiesName["北京"]["车牌"] = "京牌"
ctiesName["北京"]["景点"] = "天安门..."
//map 的遍历
// 使用for—range结构,遍历所得是键key 和 值value。(map是无序的故不可遍历得下标)
for k1, v1 := range ctiesName {
fmt.Println("k1=", k1)
for k2, v2 := range v1 {
fmt.Printf("\t k2=%v,对应的值v2=%v\n", k2, v2)
}
}
Output:
k1= 武汉
k2=景点,对应的值v2=黄鹤楼…
k2=省份,对应的值v2=湖北
k2=车牌,对应的值v2=鄂A
k1= 北京
k2=省份,对应的值v2=直辖市
k2=车牌,对应的值v2=京牌
k2=景点,对应的值v2=天安门…
统计map的长度
同样使用内建函数len()
。
map切片
基本介绍:当切片的类型是map
时,则称为slice of map,map切片s:=make([]map[type1]type)
,这样则使得map的个数可以动态变化。
案例演示:
要求使用一个map来记录monster的信息(name和age),即monster的value是一个map类型,并且怪兽的个数可动态增加(map切片)。
//map切片的使用
//1.声明一个map切片
mapSlice := make([]map[string]string, 2) //准备放入两个妖怪
//增加妖怪的信息
if mapSlice[0] == nil {
mapSlice[0] = make(map[string]string)
mapSlice[0]["name"] = "牛魔王"
mapSlice[0]["age"] = "1000岁"
}
if mapSlice[1] == nil {
mapSlice[1] = make(map[string]string)
mapSlice[1]["name"] = "猪八戒"
mapSlice[1]["age"] = "990岁"
}
fmt.Println(mapSlice) //[map[age:1000岁 name:牛魔王] map[age:990岁 name:猪八戒]]
//切片定义长度后,切片包含元素不能超过其长度(未定义容易情况下)
//下面操作会报错,越界。
// if mapSlice[2] == nil {
// mapSlice[2] = make(map[string]string)
// mapSlice[2]["name"] = "蜘蛛精"
// mapSlice[2]["age"] = "999岁"
// }
//使用切片的动态append函数,可动态增加monster的
//1.新建一个monster信息
monster := map[string]string{
"name": "金角大王",
"age": "1000岁",
}
mapSlice = append(mapSlice, monster)
fmt.Println(mapSlice)
//[map[age:1000岁 name:牛魔王] map[age:990岁 name:猪八戒] map[age:1000岁 name:金角大王]]
// 2.直接增加map内容
mapSlice = append(mapSlice, map[string]string{"name": "孙悟空", "age": "1500岁"})
fmt.Println(mapSlice)
// [map[age:1000岁 name:牛魔王] map[age:990岁 name:猪八戒] map[age:1000岁 name:金角大王] map[age:1500岁 name:孙悟空]]
fmt.Println(mapSlice[2], mapSlice[3]) //map[age:1000岁 name:金角大王] map[age:1500岁 name:孙悟空]
Noting:
1)map的使用时,在声明\定义时,未定义长度\定义了长度情况下都是可以无限创建key-value对的,即map映射会具有动态增加自身长度的功能。
m := make(map[int]string, 2)
m[1] = "abc"
m[2] = "abcd"
fmt.Println(m) //map[1:abc 2:abcd]
fmt.Println(len(m)) //2
//再增加一个关联数组则也不会报错
m[3] = "bcd"
fmt.Println(m) //map[1:abc 2:abcd 3:bcd]
fmt.Println(len(m)) //3
2)不可对已存在的map
映射直接进行切片处理,因为map
本质上键值对集合是无序的。
3)若想将已有的map
内容赋给某切片,可以使用map切片+append
方法
monster := map[string]string{
"name": "金角大王",
"age": "1000岁",
}
//2)
//noting
//不可对已存在的`map`映射直接进行切片处理,因为`map`本质上键值对集合是无序的。
//下面操作报错,不可对map进行切片
// mapSlice02 := monster[:]
//3)
mapSlice1 := make([]map[string]string, 0)
mapSlice1 = append(mapSlice1, monster)
fmt.Println(mapSlice1)//[map[age:1000岁 name:金角大王]]
map排序
基本介绍:
1)golang中没有一个专门的方法针对map的key进行排序
2)golang中的map默认是无序的,注意:也不是按照添加的顺序存放,每次遍历得到的输出结果都可能不一样的
3)golang中map的排序,先是将key进行切片化处理,使用sort
函数包进行排序,然后根据key值遍历输出
m := make(map[int]string, 10)
m[0] = "1"
m[1] = "2"
m[2] = "3"
m[9] = "6"
fmt.Println(m)
for k, v := range m {
fmt.Printf("key=%v,value=%v\n", k, v)
} //输出结果是无序的
// 要求按照map的key的顺序进行排序输出
// 1.先将map的key放入到切片中
// 2.对切片进行排序
// 3.遍历切片,然后按照key来输出map的值
var keys []int
for k := range m {
keys = append(keys, k)
}
//排序 升序
sort.Ints(keys)
fmt.Println(keys) //[0 1 2 9]
for _, v := range keys {
fmt.Printf("m[%v]=%v\n", v, m[v])
}
/* m[0] = 1
m[1] = 2
m[2] = 3
m[9] = 6 */
fmt.Println()
//排序 降序
sort.Sort(sort.Reverse(sort.IntSlice(keys)))
for _, v := range keys {
fmt.Printf("m[%v]=%v\n", v, m[v])
}
/*m[9] = 6
m[2] = 3
m[1] = 2
m[0] = 1 */
map使用细节
1)map是引用类型,遵守引用类型地址传递机制(地址传递)。在一个函数接收map,修改后,会直接修改原来的map。
func modify(m map[int]int) {
m[10] = 100
}
func main() {
m := make(map[int]int)
m[1] = 10
m[2] = 130
m[10] = 18
m[20] = 119
modify(m)
fmt.Println(m)
//map[1:10 2:130 10:100 20:119] 说明map是引用类型
2)map的容量达到后,再想增加map的元素,会自动扩容,并不会发生panic,即map能动态的增长键值对。
3)map的value
也经常是struct
类型,更适合管理复杂的数据。
type stuInfo struct {
Name string
Age int
Sex string
Address string
}
func main() {
studenMap := make(map[string]stuInfo)
//定义结构体 再赋值
stu0 := stuInfo{Name: "Alex", Age: 18, Sex: "男", Address: "武汉"}
stu1 := stuInfo{"Alice", 18, "女", "南京"}
studenMap["1020"] = stu0
studenMap["1021"] = stu1
//直接赋值
studenMap["1022"] = stuInfo{"Ming", 18, "男", "北京"}
fmt.Println(studenMap)
// map[1020:{Alex 18 男 武汉} 1021:{Alice 18 女 南京} 1022:{Ming 18 男 北京}]
// 遍历形式
for k, v := range studenMap {
fmt.Printf("学生的学号是%v\n", k)
fmt.Printf("\t学生的名字是%v\n", v.Name)
fmt.Printf("\t学生的年龄是%v\n", v.Age)
fmt.Printf("\t学生的性别是%v\n", v.Sex)
fmt.Printf("\t学生的地址是%v\n", v.Address)
fmt.Println()
}
/* 学生的学号是1020
学生的名字是Alex
学生的年龄是18
学生的性别是男
学生的地址是武汉
....
}