Golang map

map 基本介绍

  1. map 是 key-value 数据结构,又称为字段或者关联数组。类似其他编程语言的集合,在编程中是经常使用到。

    map 声明

  2. 基本语法

    1. var map变量名 map[keytype]valuetype
  3. keytype 可以的类型

    • Golang 中的 map 的 key 可以是很多种类型,比如 bool,数组,string,指针,channel,还可以只是包含前面几个类型的接口,结构体,数组。通常为 int、string 。
    • slice, map 还有 function 不可以,因为这几个没法用 == 来判断
  4. valuetype 可以是什么类型
    • valuetype 的类型和 key 基本一样
    • 通常为:数字(整数、浮点数),string,map,struct
  5. map 声明

    1. var a map[string]string
    2. var a map[string]int
    3. var a map[int][string]
    4. var a map[string]map[string]string
    5. // 注意:声明是不会分配内存的,初始化需要 make ,分配内存后才能赋值和使用。
  6. 案例一 ```go package main

import “fmt”

func main() { //map 的声明和注意事项 var a map[string]string //a[“no1”] = “宋江” 如果不 make,直接赋值就会 panic //在使用 map 前,需要 make ,make 的作用就是给 map 分配数据空间 a = make(map[string]string, 10) a[“no1”] = “宋江” a[“no2”] = “吴用” a[“no1”] = “武松” // key 不能重复,相同 key 会覆盖 a[“no3”] = “吴用” // value 可以重复 // Golang 中 map 是 key 无序的。 fmt.Println(a) }

  1. 6. 代码说明
  2. - map 在使用前一定 make
  3. - map key 不能重复,如果重复了,则以最后的 key-value
  4. - map value 是可以相同的。
  5. - map key-value 是无序的。
  6. <a name="cb482301"></a>
  7. ## map 使用
  8. 1. map 的使用方式有以下多种,分别演示。
  9. 1. 方式一
  10. ```go
  11. package main
  12. import "fmt"
  13. func main() {
  14. //第一种使用方式
  15. var a map[string]string
  16. //a["no1"] = "宋江" 如果不 make,直接赋值就会 panic
  17. //在使用 map 前,需要 make ,make 的作用就是给 map 分配数据空间
  18. a = make(map[string]string, 10)
  19. a["no1"] = "宋江"
  20. a["no2"] = "吴用"
  21. a["no1"] = "武松" // key 不能重复,相同 key 会覆盖
  22. a["no3"] = "吴用" // value 可以重复
  23. // Golang map 的 key-value 是无序的。
  24. fmt.Println(a)
  25. }
  1. 方式二 ```go package main

import “fmt”

func main() { //第二种使用方式 cites := make(map[string]string) cites[“no1”] = “北京” cites[“no2”] = “天津” cites[“no3”] = “上海”

  1. fmt.Println(cites)
  2. //第三种方式
  3. heros := map[string]string{"hero1": "宋江", "hero2": "卢俊义", "hero3": "吴用"}
  4. fmt.Println(heros)

}

  1. 4. 方式三
  2. ```go
  3. package main
  4. import "fmt"
  5. func main() {
  6. //第三种方式
  7. heros := map[string]string{"hero1": "宋江", "hero2": "卢俊义", "hero3": "吴用"}
  8. heros["hero4"] = "林冲"
  9. fmt.Println("heros =", heros)
  10. }
  1. 应用案例 ```go package main

import “fmt”

/ 应用案例: 演示一个 key-value 的 value 是 map 的实例。 比如:我们要存放 3 个学生信息,每个学生有 name 和 sex 信息。 /

func main() { studentMap := make(map[string]map[string]string)

  1. studentMap["stu01"] = make(map[string]string, 3)
  2. studentMap["stu01"]["name"] = "Tom"
  3. studentMap["stu01"]["sex"] = "男"
  4. studentMap["stu01"]["address"] = "北京长安街~"
  5. studentMap["stu02"] = make(map[string]string, 3) //这句话不能少
  6. studentMap["stu02"]["name"] = "Mary"
  7. studentMap["stu02"]["sex"] = "女"
  8. studentMap["stu02"]["address"] = "上海黄浦江~"
  9. fmt.Println(studentMap)
  10. fmt.Println(studentMap["stu02"])
  11. fmt.Println(studentMap["stu02"]["address"])

}

  1. <a name="98bd5691"></a>
  2. ## map 增删改查操作
  3. 1. map 增加和更新
  4. ```go
  5. map["key"] = value //如果可以没有,就是增加,如果可以存在就是修改。
  1. 案例一 ```go package main

import “fmt”

func main() {

  1. cites := make(map[string]string)
  2. cites["no1"] = "北京"
  3. cites["no2"] = "天津"
  4. cites["no3"] = "上海"
  5. fmt.Println(cites)
  6. //因为 no3 这个 key 已经存在,因此下面的这句话就是修改
  7. cites["no3"] = "上海~"
  8. fmt.Println(cites)

}

  1. 3. map 删除
  2. ```go
  3. delete(map, "key") // delete 是个内置函数,如果 key 存在,就删除该 key-value,如果 key 不存在,不操作,但是也不会报错。
  1. 案例二 ```go package main

import “fmt”

func main() {

  1. // map 增加和更新
  2. cites := make(map[string]string)
  3. cites["no1"] = "北京"
  4. cites["no2"] = "天津"
  5. cites["no3"] = "上海"
  6. fmt.Println(cites)
  7. //因为 no3 这个 key 已经存在,因此下面的这句话就是修改
  8. cites["no3"] = "上海~"
  9. fmt.Println(cites)
  10. //map 删除
  11. delete(cites, "no1")
  12. fmt.Println(cites)
  13. //当 delete 指定的 key 不存在时,删除不会操作,也不会报错。
  14. delete(cites, "no4")
  15. fmt.Println(cites)

}

  1. 5. map 删除细节说明:
  2. - 如果我们要删除 map 的所有 key ,没有一个专门的方法一次删除,可以遍历一下 key ,逐个删除。
  3. - 或者 map = make(...),make 一个新的,让原来的成为垃圾,被 gc 回收。
  4. 6. 案例三
  5. ```go
  6. package main
  7. import "fmt"
  8. func main() {
  9. // map 增加和更新
  10. cites := make(map[string]string)
  11. cites["no1"] = "北京"
  12. cites["no2"] = "天津"
  13. cites["no3"] = "上海"
  14. fmt.Println(cites)
  15. //因为 no3 这个 key 已经存在,因此下面的这句话就是修改
  16. cites["no3"] = "上海~"
  17. fmt.Println(cites)
  18. //map 删除
  19. delete(cites, "no1")
  20. fmt.Println(cites)
  21. //当 delete 指定的 key 不存在时,删除不会操作,也不会报错。
  22. delete(cites, "no4")
  23. fmt.Println(cites)
  24. //如果希望一次性删除所有的 key
  25. //1. 遍历删除
  26. //2. 直接 make 一个新空间
  27. cites = make(map[string]string)
  28. fmt.Println(cites)
  29. }
  1. map 查找 ```go package main

import “fmt”

func main() {

  1. // map 增加和更新
  2. cites := make(map[string]string)
  3. cites["no1"] = "北京"
  4. cites["no2"] = "天津"
  5. cites["no3"] = "上海"
  6. fmt.Println(cites)
  7. //因为 no3 这个 key 已经存在,因此下面的这句话就是修改
  8. cites["no3"] = "上海~"
  9. fmt.Println(cites)
  10. //map 删除
  11. delete(cites, "no1")
  12. fmt.Println(cites)
  13. //当 delete 指定的 key 不存在时,删除不会操作,也不会报错。
  14. delete(cites, "no4")
  15. fmt.Println(cites)
  16. //map 查找
  17. val, findRes := cites["no2"]
  18. if findRes {
  19. fmt.Printf("有 no1 key 值为%v\n", val)
  20. } else {
  21. fmt.Printf("没有 no1 key\n")
  22. }
  23. //如果希望一次性删除所有的 key
  24. //1. 遍历删除
  25. //2. 直接 make 一个新空间
  26. cites = make(map[string]string)
  27. fmt.Println(cites)

}

  1. 8. 代码说明
  2. - 如果 cites 这个 map 中存在 "no1" ,那么 findRes 就会返回 true,否则返回 false
  3. <a name="49634f3a"></a>
  4. ## map 遍历
  5. 1. map 的遍历使用 for-range 的结构遍历
  6. 1. 案例一
  7. ```go
  8. package main
  9. import (
  10. "fmt"
  11. )
  12. func main() {
  13. //使用 for-range 遍历 map
  14. cites := make(map[string]string)
  15. cites["no1"] = "北京"
  16. cites["no2"] = "天津"
  17. cites["no3"] = "上海"
  18. for key, value := range cites {
  19. fmt.Printf("key = %v value = %v\n", key, value)
  20. }
  21. //使用 for-range 遍历一个结构比较复杂的 map
  22. studentMap := make(map[string]map[string]string)
  23. studentMap["stu01"] = make(map[string]string, 3)
  24. studentMap["stu01"]["name"] = "Tom"
  25. studentMap["stu01"]["sex"] = "男"
  26. studentMap["stu01"]["address"] = "北京长安街~"
  27. studentMap["stu02"] = make(map[string]string, 3) // 这句话不能少
  28. studentMap["stu02"]["name"] = "Mary"
  29. studentMap["stu02"]["sex"] = "女"
  30. studentMap["stu02"]["address"] = "上海黄浦江~"
  31. for key1, value1 := range studentMap {
  32. fmt.Println("key1 =", key1)
  33. for key2, value2 := range value1 {
  34. fmt.Printf("\t key2 = %v value2 = %v\n", key2, value2)
  35. }
  36. }
  37. }

map 长度

  1. 案例一 ```go package main

import ( “fmt” )

func main() { //使用 for-range 遍历 map

  1. cites := make(map[string]string)
  2. cites["no1"] = "北京"
  3. cites["no2"] = "天津"
  4. cites["no3"] = "上海"
  5. for key, value := range cites {
  6. fmt.Printf("key = %v value = %v\n", key, value)
  7. }
  8. //求 map 长度
  9. fmt.Println("cites 有", len(cites), "对 key-value")

}

  1. <a name="6b89d92f"></a>
  2. ## map 切片
  3. <a name="f72dd4a6"></a>
  4. ### 基本介绍
  5. 1. 切片的数据类型如果是 map ,则我们称为 slice of map, map 切片,这样使用则 map 个数就可以动态变化了。
  6. 1. 案例一:使用一个 map 来记录 monster 的信息 name 和 age ,也就是说一个 monster 对应一个 map ,并且妖怪的个数可以动态的增加 => map 切片。
  7. ```go
  8. package main
  9. import "fmt"
  10. func main() {
  11. /*
  12. 要求:使用一个 map 来记录 monster 的信息 name 和 age,也就是说一个 monster 对应一个 map,
  13. 并且妖怪的个数可以动态的增加 => map 切片。
  14. */
  15. //1. 声明一个 map 切片
  16. var monsters []map[string]string
  17. monsters = make([]map[string]string, 2) //准备放入两个妖怪
  18. //2. 增加第一个妖怪信息
  19. if monsters[0] == nil {
  20. monsters[0] = make(map[string]string, 2)
  21. monsters[0]["name"] = "牛魔王"
  22. monsters[0]["age"] = "500"
  23. }
  24. if monsters[1] == nil {
  25. monsters[1] = make(map[string]string, 2)
  26. monsters[1]["name"] = "玉兔精"
  27. monsters[1]["age"] = "400"
  28. }
  29. //下面这个写法越界了
  30. //if monsters[2] == nil {
  31. // monsters[2] = make(map[string]string, 2)
  32. // monsters[2]["name"] = "狐狸精"
  33. // monsters[2]["age"] = "400"
  34. //}
  35. //这里我们需要使用到切片的 append 函数,可以动态的增加 monster
  36. //先定义一个 monster 信息
  37. newMonster := map[string]string{
  38. "name": "新妖怪~火云邪神",
  39. "age": "200",
  40. }
  41. monsters = append(monsters, newMonster)
  42. fmt.Println(monsters)
  43. }

map 排序

基本介绍

  1. Golang 中没有一个专门的方法针对 map 的 key 进行排序。
  2. Golang 中的 map 默认是无序的,注意也不是按照添加的顺序存放的,你每次遍历输出的结果可能不一样。
  3. Golang 中的 map 的排序,是先将 key 进行排序,然后根据 key 值遍历输出即可。
  4. 案例一 ```go package main

import ( “fmt” “sort” )

func main() {

  1. //map 的排序
  2. map1 := make(map[int]int, 10)
  3. map1[10] = 100
  4. map1[1] = 13
  5. map1[4] = 56
  6. map1[8] = 90
  7. fmt.Println(map1)
  8. //如果按照 map 的 key 的顺序进行排序输出
  9. //1. 先将 map 的 key 放入切片中
  10. //2. 对切片排序
  11. //3. 遍历切片,然后按照 key 来输出 map 的值
  12. var keys []int
  13. for key, _ := range map1 {
  14. keys = append(keys, key)
  15. }
  16. //排序
  17. sort.Ints(keys)
  18. fmt.Println(keys)
  19. for _, key := range keys {
  20. fmt.Printf("map1[%v] = %v \n", key, map1[key])
  21. }

}

  1. <a name="e21bcebf"></a>
  2. ## map 使用细节
  3. 1. map 是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改原来的 map 。
  4. ```go
  5. package main
  6. import "fmt"
  7. func modify(map1 map[int]int) {
  8. map1[10] = 900
  9. }
  10. func main() {
  11. //map 是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改原来的 map。
  12. map1 := make(map[int]int)
  13. map1[1] = 90
  14. map1[2] = 88
  15. map1[10] = 1
  16. map1[20] = 2
  17. modify(map1)
  18. fmt.Println(map1) //看结果 map[1:90 2:88 10:900 20:2] ,则说明 map 为引用类型。
  19. }
  1. map 的容量达到后,再想 map 增加函数,会自动扩容,并不会发生 panic ,也就是说 map 能动态地增长键值对 (key-value) 。 ```go package main

import “fmt”

func modify(map1 map[int]int) { map1[10] = 900 }

func main() { // map 是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改原来的 map 。 map1 := make(map[int]int, 2)

  1. map1[1] = 90
  2. map1[2] = 88
  3. map1[10] = 1
  4. map1[20] = 2 // map 可以自动扩容
  5. modify(map1)
  6. fmt.Println(map1) //看结果 map[1:90 2:88 10:900 20:2] ,则说明 map 为引用类型。

}

  1. 3. map value 也经常使用 struct 类型,更适合管理复杂的数据(比前面 value 是一个 map 更好)。
  2. ```go
  3. package main
  4. import "fmt"
  5. //定义一个学生结构体
  6. type stu struct {
  7. Name string
  8. Age int
  9. Address string
  10. }
  11. func main() {
  12. // map 的 value 也经常使用 struct 类型,更适合管理复杂的数据(比前面 value 是一个 map 更好)。
  13. // 1. map 的 key 为学生的学号,是唯一的。
  14. // 2. map 的 value 为结构体,包含学生的 名字,年龄,地址
  15. students := make(map[string]stu, 10)
  16. //创建两个学生
  17. stu1 := stu{"Tom", 18, "北京"}
  18. stu2 := stu{"Mary", 28, "上海"}
  19. students["no1"] = stu1
  20. students["no2"] = stu2
  21. fmt.Println(students)
  22. fmt.Println()
  23. //遍历各个学生信息
  24. for key, value := range students {
  25. fmt.Printf("学生的编号是 %v \n", key)
  26. fmt.Printf("学生的名字是 %v \n", value.Name)
  27. fmt.Printf("学生的年龄是 %v \n", value.Age)
  28. fmt.Printf("学生的地址是 %v \n", value.Address)
  29. fmt.Println()
  30. }
  31. }

课堂练习

  1. 练习要求
    • 使用 map[string]map[string]string 的 map 类型。
    • key:表示用户名,是唯一的,不可以重复。
    • 如果某个用户存在,就将其密码修改 “888888”,如果不存在就增加这个用户信息。(包括昵称(nickname 和 密码 pwd))。
    • 编写一个函数 modifyUser(user map[string]map[string]string, name string)完成上述功能。
  2. 练习一 ```go package main

import “fmt”

/ 课堂练习: (1) 使用 map[string]map[string]string 的 map 类型。 (2) key:表示用户名,是唯一的,不可以重复。 (3) 如果某个用户存在,就将其密码修改 888888 ,如果不存在就增加这个用户信息。(包括昵称(nickname 和 密码 pwd))。 (4) 编写一个函数 modifyUser(user map[string]map[string]string, name string)完成上述功能。 /

func modifyUser(users map[string]map[string]string, name string) {

  1. //判断 user 中是否有 name
  2. //v, ok := user[name]
  3. if users[name] != nil {
  4. // 有这个用户
  5. users[name]["pwd"] = "888888"
  6. } else {
  7. //目前没有这个用户
  8. users[name] = make(map[string]string, 2)
  9. users[name]["pwd"] = "888888"
  10. users[name]["nikcename"] = "昵称~" + name //示意
  11. }

}

func main() { users := make(map[string]map[string]string, 10) users[“Smith”] = make(map[string]string, 2) users[“Smith”][“pwd”] = “999999” users[“Smith”][“nikename”] = “小花猫”

  1. modifyUser(users, "Tom")
  2. modifyUser(users, "Marry")
  3. modifyUser(users, "Smith")
  4. fmt.Println(users)

} ```


课程来源