九、MAP
map 是 key-value 数据结构,又称为字段或者关联数组。类似其它编程语言的集合, 在编程中是经常使用到
var map 变量名 map[keytype]valuetype
key 可以是什么类型
- bool, 数字,string, 指针, channel , 还可以是只 包含前面几个类型的 接口, 结构体, 数组 , 通常 key 为 int 、string 注意: slice, map 还有 function 不可以,因为这几个没法用 == 来判断
valuetype 可以是什么类型
- valuetype 的类型和 key 基本一样 , 通常为: 数字(整数,浮点数),string,map,struct
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string
注意:声明是不会分配内存的,初始化需要 make ,分配内存后才能赋值和使用。
var a map[string]string //map[]
//map声明是不会分配内存的,初始化需要 make ,分配内存后才能赋值和使用
//a["n01"] = "宋江" //panic: assignment to entry in nil map
//使用前先make,分配数据空间,数组声明时候就分配
a = make(map[string]string, 10)
a["n01"] = "宋江" //map[n01:宋江]
a["n02"] = "吴用1" //map[n01:武松 n02:吴用]
a["n01"] = "武松" //key不能重复,会被覆盖
a["n03"] = "吴用2" //value可以
//test
//顺序问题
//map[n01:武松 n02:吴用1 n03:吴用2]
//map[n01:武松 n02:吴用1 n03:吴用2]
fmt.Println(a)
map 在使用前一定要 make
map 的 key 是不能重复,如果重复了,则以最后这个 key-value 为准
map 的 value 是可以相同的
map 的 key-value 是无序
make 内置函数数目
- size可以省略,第一个表示分配的常量,第二个为容量。容量不能小于长度
默认分配一个小的初始大小
- 先声明 再make
- 声明的时候同时make
- 声明,直接赋值
//第一种方式
var a map[string]string //map[]
//map声明是不会分配内存的,初始化需要 make ,分配内存后才能赋值和使用
//a["n01"] = "宋江" //panic: assignment to entry in nil map
//使用前先make,分配数据空间,数组声明时候就分配
a = make(map[string]string, 10)
a["n01"] = "宋江" //map[n01:宋江]
a["n02"] = "吴用1" //map[n01:武松 n02:吴用]
a["n01"] = "武松" //key不能重复,会被覆盖
a["n03"] = "吴用2" //value可以
//test
//顺序问题
//map[n01:武松 n02:吴用1 n03:吴用2]
//map[n01:武松 n02:吴用1 n03:吴用2]
fmt.Println(a)
//第二种方式 常用
cities := make(map[string]string)
cities["n01"] = "深圳"
cities["n02"] = "北京"
cities["n03"] = "上海"
fmt.Println(cities) //map[n01:深圳 n02:北京 n03:上海]
//第三种方式
heroes := map[string]string{
"hero01": "1",
"hero02": "2",
"hero03": "3",
}
heroes["hero04"] = "4"
fmt.Println(heroes) //map[hero01:1 hero02:2 hero03:3]
map 使用的课堂案例
演示一个 key-value 的 value 是 map 的案例
比如:我们要存放 3 个学生信息, 每个学生有 name 和 sex 信息
思路: map[string]map[string]string
studentMap := make(map[string]map[string]string)
studentMap["stu01"] = make(map[string]string, 2)
studentMap["stu01"]["name"] = "tome"
studentMap["stu01"]["age"] = "12"
studentMap["stu01"]["city"] = "shenzhen"
studentMap["stu02"] = make(map[string]string, 2)
studentMap["stu02"]["name"] = "joy"
studentMap["stu02"]["age"] = "11"
studentMap["stu02"]["city"] = "shanghai"
fmt.Println(studentMap)
fmt.Println(studentMap["stu01"])
fmt.Println(studentMap["stu02"])
-----------------------------------------
map[stu01:map[age:12 city:shenzhen name:tome] stu02:map[age:11 city:shanghai name:joy]]
map[age:12 city:shenzhen name:tome]
map[age:11 city:shanghai name:joy]
其实就是集合,也就是json
//第二种方式 常用
cities := make(map[string]string)
cities["n01"] = "深圳"
cities["n02"] = "北京"
cities["n03"] = "上海"
fmt.Println(cities) //map[n01:深圳 n02:北京 n03:上海]
//map["key"] = value key存在就是增加不存在就是修改
cities["n03"] = "重庆"
fmt.Println(cities)
//delete(map,"key") 如果 key 存在,就删除该 key-value,如果 key 不存在,
//不操作,但是也不会报错
delete(cities, "n03")
fmt.Println(cities)
//删除所有map的key,要么遍历key逐个删除,要么map=make()来make新的map
cities = make(map[string]string)
//查找
value, ok := cities["n02"]
if ok {
fmt.Println("no %v\n", value)
} else {
fmt.Println("no")
}
一维的map
cities := make(map[string]string)
cities["n01"] = "深圳"
cities["n02"] = "北京"
cities["n03"] = "上海"
for k, v := range cities {
fmt.Printf("k=%v v=%v\n", k, v)
}
----------------------------------------------
k=n03 v=上海
k=n01 v=深圳
k=n02 v=北京
-----------------------------------------------
二位的map,map的值也是map, 先循环取出一个map,再循环取出值
studentMap := make(map[string]map[string]string)
studentMap["stu01"] = make(map[string]string, 2)
studentMap["stu01"]["name"] = "tome"
studentMap["stu01"]["age"] = "12"
studentMap["stu01"]["city"] = "shenzhen"
studentMap["stu02"] = make(map[string]string, 2)
studentMap["stu02"]["name"] = "joy"
studentMap["stu02"]["age"] = "11"
studentMap["stu02"]["city"] = "shanghai"
for k1, v1 := range studentMap {
fmt.Println("k=", k1)
for k2, v2 := range v1 {
fmt.Printf("\t k2=%v v2=%v\n", k2, v2)
}
fmt.Println()
}
------------------------------------------------
k= stu02
k2=name v2=joy
k2=age v2=11
k2=city v2=shanghai
k= stu01
k2=age v2=12
k2=city v2=shenzhen
k2=name v2=tome
------------------------------------------------
func len
func len(v Type) int
内建函数len返回 v 的长度,这取决于具体类型:
数组:v中元素的数量
数组指针:*v中元素的数量(v为nil时panic)
切片、映射:v中元素的数量;若v为nil,len(v)即为零
字符串:v中字节的数量
通道:通道缓存中队列(未读取)元素的数量;若v为 nil,len(v)即为零
切片的数据类型如果是 map,则我们称为 slice of map,map 切片,这样使用则 map 个数就可以动
态变化了
使用一个 map 来记录 monster 的信息 name 和 age, 也就是说一个 monster 对应一个 map,并
且妖怪的个数可以动态的增加=>map 切片
var monsters []map[string]string
monsters = make([]map[string]string, 2)
//增加信息
if monsters[0] == nil {
monsters[0] = make(map[string]string, 2)
monsters[0]["name"] = "牛魔王"
monsters[0]["age"] = "500"
}
if monsters[1] == nil {
monsters[1] = make(map[string]string)
monsters[1]["name"] = "猴子"
monsters[1]["age"] = "5000"
}
//越界 panic: runtime error: index out of range [2] with length 2
//if monsters[2] == nil {
// monsters[2] = make(map[string]string)
// monsters[2]["name"] = "猴子"
// monsters[2]["age"] = "5000"
//}
//针对越界问题,go有append函数动态增加monster
//1. 先定义个monster信息
newMonster := map[string]string{
"name": "new",
"age": "200",
}
monsters = append(monsters, newMonster)
fmt.Println(monsters)
map 排序
golang 中没有一个专门的方法针对 map 的 key 进行排序
golang 中的 map 默认是无序的,注意也不是按照添加的顺序存放的,每次遍历,得到的输出 可能不一样
golang 中 map 的排序,是先将 key 进行排序,然后根据 key 值遍历输出即可
//map排序
map1 := make(map[int]int, 10)
map1[10] = 100
map1[1] = 1
map1[3] = 3
map1[8] = 8
fmt.Println(map1)
//如果安装map的key的顺序仅需排序输出
//1. 先将map的key放入到切片中
//2. 对切片排序
//3. 遍历切片,然后按照key来输出map的值
var keys []int
for k, _ := range map1 {
keys = append(keys, k)
}
sort.Ints(keys)
fmt.Println(keys)
for _, k := range keys {
fmt.Printf("map1[%v]=%v\n", k, map1[k])
}
-----------------------------------------
map[1:1 3:3 8:8 10:100]
[1 3 8 10]
map1[1]=1
map1[3]=3
map1[8]=8
map1[10]=100
-----------------------------------------
map 使用细节
map 是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改原来 的 map
map 的容量达到后,再想 map 增加元素,会自动扩容,并不会发生 panic,也就是说 map 能动 态的增长 键值对(key-value)
map 的 value 也经常使用 struct 类型,更适合管理复杂的数据(比前面 value 是一个 map 更好) , 比如 value 为 Student 结构体
map 的课堂练习题
- 使用 map[string]map[string]sting 的 map 类型
- key: 表示用户名,是唯一的,不可以重复
- 如果某个用户名存在,就将其密码修改”888888”,如果不存在就增加这个用户信息,(包括昵称 nickname 和 密码 pwd)。
- 编写一个函数 modifyUser(users map[string]map[string]sting, name string) 完成上述功能
本作品采用《CC 协议》,转载必须注明作者和本文链接