介绍

map是key-value数据结构,又称为字段或关联数组。
映射是一个存储键值对的无序集合。

基本语法

  1. var map变量名 map[keyType]valueType

key可以是很多类型,比如 bool, 数字, string, 指针, channel。还可以是只包含前面几个类型的接口,结构体,数组,通常为 int, string
注意: slice, map 还有 function 不可以,因为这几个没发用 == 判断

value的类型和key基本一样,通常为 数字、string ,map , struct

声明

  1. // 只声明
  2. var a map[string]string
  3. fmt.Printf("a类型: %T, 值: %v \n", a, a) // a类型: map[string]string, 值: map[]
  4. a["test"] = "xiao" // panic: assignment to entry in nil map
  5. // 使用 make 声明
  6. var cities01 = make(map[string]string)
  7. fmt.Printf("cities01 类型: %T, 值: %v \n", cities01, cities01)
  8. // cities01 类型: map[string]string, 值: map[]
  9. // 声明并赋值
  10. var cities map[string]string = map[string]string{
  11. "beijing": "北京", // 必须要写 , 逗号
  12. }
  13. fmt.Printf("cities类型: %T, 值: %v \n", cities, cities)
  14. // cities类型: map[string]string, 值: map[beijing:北京]

注意: 声明是不会分配内存的初始化需要 make , 分配内存后才可以赋值和使用。否则报错

  • make 作用就是分配空间
  • key重复的话,value值就会覆盖调原先的,
  • 不同key对应的value值可以相同
  • key是无序的,每次迭代映射的时候顺序可能不一样(原因是映射的实现使用了散列表

散列函数的目的是生成一个索引。

  1. var a map[string]string
  2. fmt.Printf("a类型: %T, 值: %v \n", a, a) // a类型: map[string]string, 值: map[]
  3. // make 作用就是分配空间
  4. a = make(map[string]string, 2) // 可以存放2个key-value
  5. a["test"] = "xiao"
  6. a["test"] = "xiao~"
  7. // key重复的话,value值就会覆盖调原先的,key是无序的
  8. fmt.Printf("a类型: %T, 值: %v \n", a, a) // a类型: map[string]string, 值: map[test:xiao~]

散列表

映射的散列表包含一组桶。在存储、删除或者查找键值对的时候,所有操作都要先选择一个桶。把操作映射时指向的键传给映射的散列函数,就能选中对应的桶。这个散列函数的目的是生成一个索引,这个索引最终将键值对分布到所有可用的桶里。
随着映射存储的增加,索引分布越均匀,访问键值对的速度越快。

映射内存

映射使用两个数据结构来存储数据

  1. 第一个数据结构是一个数组,内部存储的是用于选择桶的散列键的高八位值。这个数组用于区分每个键值对要存在哪个桶里。
  2. 第二个数据结构是一个字节数组,用于存储键值对。该字节数组依次存储了这个桶里的所有的键,之后依次存储了这个桶里所有的值。实现这种键值对的存储方式目的在于减少每个桶所需的内存。

    map使用细节:

  3. map是引用类型,遵守引用类型的传递机制,在一个函数接受map后,修改后,会直接修改原map

  4. map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态增加键值。
  5. map的value经常使用struct类型,更适合管理复杂的数据。

    练习

    多维map

    ```javascript // 练习 // 存放学生信息,学生有name和sex字段 studentMap := make(map[string]map[string]string) fmt.Printf(“studentMap 类型: %T, 值: %v \n”, studentMap, studentMap) studentMap[“01”] = make(map[string]string) studentMap[“01”][“name”] = “xiao” studentMap[“01”][“sex”] = “男”

studentMap[“02”] = make(map[string]string) studentMap[“02”][“name”] = “xiao” studentMap[“02”][“sex”] = “男” // 增加一个addr字段 studentMap[“02”][“addr”] = “上海” fmt.Println(“studentMap = “, studentMap) // studentMap = map[01:map[name:xiao sex:男] 02:map[addr:上海 name:xiao sex:男]] fmt.Printf(“studentMap[01][addr] = %q”, studentMap[“01”][“addr”]) // studentMap[01][addr] = “”

  1. <a name="ixfwT"></a>
  2. ## map 结构体(更常用)
  3. 上面存储学生信息的练习,采用结构体更加合适,且清晰简单
  4. ```javascript
  5. // map 结构体
  6. /*
  7. key是学号, 唯一的
  8. value是结构体
  9. */
  10. // 自定义结构体类型 Stu
  11. type Stu struct {
  12. Name string
  13. Age int
  14. Addr string
  15. }
  16. students := make(map[string]Stu, 10)
  17. stu1 := Stu{"tom", 10, "上海"}
  18. fmt.Printf("stu1类型:%T, 值: %v \n", stu1, stu1)
  19. // stu1类型:main.Stu, 值: {tom 10 上海}
  20. stu2 := Stu{"jerry", 9, "上海01"}
  21. students["001"] = stu1
  22. students["002"] = stu2
  23. fmt.Println("students = ", students)
  24. // students = map[001:{tom 10 上海} 002:{jerry 9 上海01}]
  25. // 遍历学生信息
  26. for k, v := range students {
  27. fmt.Printf("编号: %v\t", k)
  28. fmt.Printf("姓名: %v\t", v.Name)
  29. fmt.Printf("年龄: %v\t", v.Age)
  30. fmt.Printf("地址: %v\t", v.Addr)
  31. fmt.Println()
  32. }
  33. // 编号: 001 姓名: tom 年龄: 10 地址: 上海
  34. // 编号: 002 姓名: jerry 年龄: 9 地址: 上海01