*本文笔记参考:b站【尚硅谷】Golang入门到实战教程
map是key-value数据结构,又称为字段或关联数组。
var 变量名 map[keytype]valuetype
key的数据类型通常为int、string类型,也可以为bool、数字、指针、channel,还可以是只包含前面几个类型的接口、数组、结构体;但是,不能为slice、map、function,因为这几个没法用==判断。
value的数据类型通常为数字(整数、浮点数)、string、map、struct。
声明是不会分配内存的,初始化需要make,分配内存后才能赋值和使用。
var a map[string]string
fmt.Println(a)
// 输出:map[]
func main() {
var a map[string]string
a["no1"] = "宋江"
a["no2"] = "吴用"
a["no1"] = "武松"
a["no3"] = "吴用"
fmt.Println(a)
}
// 输出:
//panic: assignment to entry in nil map
//goroutine 1 [running]:
//main.main()
// E:/study/Go_WorkSpace/src/code/test/main.go:9 +0x32
//exit status 2
func main() {
var a map[string]string
// 使用map前,需要先make,make的作用就是给map分配数据空间
a = make(map[string]string, 10)
a["no1"] = "go"
a["no2"] = "hello"
fmt.Println(a)
}
//输出:map[no1:go no2:hello]
说明:
map在使用前一定要make;
make里如果不指定map的size,则默认size为1;
map的key不能重复,如果重复了,则以最后的key-value为准;
map的value是可以重复的;
map的key-value是无序的。
1)先声明,再make,而后赋值
func main() {
// 声明
var a map[string]string
// make
a = make(map[string]string, 2)
// 赋值
a["no1"] = "go"
fmt.Println(a)
}
2)声明时直接make,而后赋值
func main() {
// 声明时直接make
var a = make(map[string]string, 2)
// 赋值
a["no1"] = "go"
fmt.Println(a)
}
3)声明时直接赋值
func main() {
// 声明时直接赋值
a := map[string]string{
"no1": "go",
"no2": "hello",
}
fmt.Println(a)
}
4)实例:存放2个学生的信息,每个学生有sex和address信息
func main() {
// 声明时直接make
var students = make(map[string]map[string]string)
// 直接make
students["no1"] = make(map[string]string)
// 赋值
students["no1"]["sex"] = "male"
students["no1"]["address"] = "泗泾"
students["no2"] = make(map[string]string)
students["no2"]["sex"] = "female"
students["no2"]["address"] = "松江"
fmt.Println(students)
}
func main() {
// 声明时直接make
var students = make(map[string]map[string]string)
// 直接赋值
students["no1"] = map[string]string{
"sex": "male",
"address": "泗泾",
}
students["no2"] = map[string]string{
"sex": "female",
"address": "松江",
}
fmt.Println(students)
}
//输出:
//map[no1:map[address:泗泾 sex:male] no2:map[address:松江 sex:female]]
1)增加与更改
// map["key"] = value // key存在则更改,不存在则增加
func main() {
// 声明时直接赋值
a := map[string]string{
"no1": "go",
"no2": "hello",
}
a["no3"] = "hahah"
fmt.Println(a)
}
//输出:map[no1:go no2:hello no3:hahah]
2)删除
// delete(map, "key")
delete(a, "no3")
删除所有的key的方法:
没有专门的方法一次删除所有key,因此,可以遍历key,逐个删除。
func main() {
// 声明时直接赋值
a := map[string]string{
"no1": "go",
"no2": "hello",
}
a["no3"] = "hahah"
fmt.Println(a)
for i, _ := range a { //遍历key,逐个删除
delete(a, i)
}
fmt.Println(a)
}
make一个新的空间,a = make(map[string]string)
,make一个新的,让原来的成为垃圾,被GC回收。
func main() {
// 声明时直接赋值
a := map[string]string{
"no1": "go",
"no2": "hello",
}
a["no3"] = "hahah"
fmt.Println(a)
a = map[string]string{} //make一个新的空间
fmt.Println(a)
}
//输出:
//map[no1:go no2:hello no3:hahah]
//map[]
3)查找
val, findRes := a["no1"]
if findRes {
fmt.Println("有no1这个key,值为", val)
} else {
fmt.Println("没有no1这个key")
}
不能用for循环遍历,因为map的下标不一定是数字。使用for-range遍历:
for k, v := range a {
fmt.Printf("k=%v, v=%v\n", k, v)
}
map的长度:len(a)
map切片使map的个数动态变化(注意,是map的个数,不是一个map中key-value的个数)。
例:使用一个map记录monster的信息name和age,即一个monster对应一个map,并且monster的个数可以动态增加:
func main() {
// 先声明,再make,再赋值
var monster []map[string]string
monster = make([]map[string]string, 2)
monster[0] = make(map[string]string)
monster[0]["name"] = "monkey"
monster[0]["age"] = "50"
// 声明时直接赋值
newMonster := map[string]string{
"name": "elephant",
"age": "100",
}
//原来monster有2个map,增加1个,现在有3个map
monster = append(monster, newMonster)
fmt.Println(monster)
}
//输出:[map[age:50 name:monkey] map[] map[age:100 name:elephant]]
golang中没有专门的方法对map的key排序;
golang中的map默认是无序的,也不是按照添加的顺序存放,每次遍历,得到的结果可能都不同;
golang中map的排序,是先将key进行排序,然后根据key值遍历输出即可:将map的key放入到切片中,对切片排序,然后根据key值遍历输出。
func main() {
// map的排序
map1 := make(map[int]int, 10)
map1[10] = 10
map1[1] = 1
map1[8] = 8
map1[4] = 4
map1[6] = 6
// 将map的key放入切片中
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", k, map1[k])
}
}
//输出
[1 4 6 8 10]
map1[1]=1 map1[4]=4 map1[6]=6 map1[8]=8 map1[10]=10
map是引用类型,在一个函数接收map,修改后,会直接修改原来的map;
map能动态增长键值对(map-key):map的容量达到上限后,再想增加map元素,会自动扩容,并不会发生panic;但是切片的动态增长需要用到append;
map的value也经常使用struct类型,更适合管理复杂的数据(比双层map更好);
package main
import (
"fmt"
)
type Stu struct {
Sex string
Address string
}
func main() {
//map的key为int类型,value为结构体
var students = make(map[string]Stu)
students["no1"] = Stu{"male", "泗泾"}
students["no2"] = Stu{"female", "松江"}
fmt.Println(students)
}
//输出
map[no1:{male 泗泾} no2:{female 松江}]
使用map[string]map[string]string
的map类型,key
表示用户名,是唯一的,不可以重复。如果某个用户存在,就将其密码修改为“888888”,如果不存在就增加这个用户信息(包括昵称nickname 和 密码pwd)。编写一个函数 modifyUser(users map[string]map[string]string)
完成上述功能。
package main
import "fmt"
func modifyUser(users map[string]map[string]string, name string) {
//判断users中是否有该用户名
if users[name] != nil {
users[name]["pwd"] = "888888"
} else {
users[name] = map[string]string{
"nickname": name,
"pwd": "888888",
}
}
}
func main() {
users := make(map[string]map[string]string, 10)
users["tom"] = map[string]string{
"pwd": "123456",
"nickname": "tom",
}
modifyUser(users, "tom")
modifyUser(users, "mary")
fmt.Println(users)
}
//输出
map[mary:map[nickname:mary pwd:888888] tom:map[nickname:tom pwd:888888]]