7.5.1 map创建

要求所有的key的数据类型相同,所有value数据类型相同(注:key与value可以有不同的数据类型)

  1. // 1 字面值
  2. {
  3. m1 := map[string]string{
  4. "m1": "v1", // 定义时指定的初始key/value, 后面可以继续添加
  5. }
  6. _ = m1
  7. }
  8. // 2 使用make函数
  9. {
  10. m2 := make(map[string]string) // 创建时,里面不含元素,元素都需要后续添加
  11. m2["m2"] = "v2" // 添加元素
  12. _ = m2
  13. }
  14. // 定义一个空的map
  15. {
  16. m3 := map[string]string{}
  17. m4 := make(map[string]string)
  18. _ = m3
  19. _ = m4
  20. }

7.5.2 map中key的类型

map中的每个key在keys的集合中是唯一的,而且需要支持 == or != 操作
key的常用类型:int, rune, string, 结构体(每个元素需要支持 == or != 操作), 指针, 基于这些类型自定义的类型

  1. // m0 可以, key类型为string, 支持 == 比较操作
  2. {
  3. var m0 map[string]string // 定义map类型变量m0key的类型为stringvalue的类型string
  4. fmt.Println(m0)
  5. }
  6. // m1 不可以, []byteslice,不支持 == != 操作,不可以作为map key的数据类型
  7. {
  8. //var m1 map[[]byte]string // 报错: invalid map key type []byte
  9. //fmt.Println(m1)
  10. // 准确说slice类型只能与nil比较,其他的都不可以,可以通过如下测试:
  11. // var b1,b2 []byte
  12. // fmt.Println(b1==b2) // 报错: invalid operation: b1 == b2 (slice can only be compared to nil)
  13. }
  14. // m2 可以, interface{}类型可以作为key,但是需要加入的key的类型是可以比较的
  15. {
  16. var m2 map[interface{}]string
  17. m2 = make(map[interface{}]string)
  18. //m2[[]byte("k2")]="v2" // panic: runtime error: hash of unhashable type []uint8
  19. m2[123] = "123"
  20. m2[12.3] = "123"
  21. fmt.Println(m2)
  22. }
  23. // m3 可以, 数组支持比较
  24. {
  25. a3 := [3]int{1, 2, 3}
  26. var m3 map[[3]int]string
  27. m3 = make(map[[3]int]string)
  28. m3[a3] = "m3"
  29. fmt.Println(m3)
  30. }
  31. // m4 可以,book1里面的元素都是支持== !=
  32. {
  33. type book1 struct {
  34. name string
  35. }
  36. var m4 map[book1]string
  37. fmt.Println(m4)
  38. }
  39. // m5 不可以, text元素类型为[]byte, 不满足key的要求
  40. {
  41. // type book2 struct {
  42. // name string
  43. // text []byte //没有这个就可以
  44. // }
  45. //var m5 map[book2]string //invalid map key type book2
  46. //fmt.Println(m5)
  47. }

7.5.3 map的增删改

  1. // 创建
  2. m := map[string]string{
  3. "a": "va",
  4. "b": "vb",
  5. }
  6. fmt.Println(len(m)) // len(m) 获得m中key/value对的个数
  7. // 增加,修改
  8. {
  9. // k不存在为增加,k存在为修改
  10. m["c"] = ""
  11. m["c"] = "11" // 重复增加(key相同),使用新的值覆盖
  12. fmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"a":"va", "b":"vb", "c":"11"} 3
  13. }
  14. // 查
  15. {
  16. // v := m[k] // 从m中取键k对应的值给v,如果k在m中不存在,则将value类型的零值赋值给v
  17. // v, ok := m[k] // 从m中取键k对应的值给v,如果k存在,ok=true,如果k不存在,将value类型的零值赋值给v同时ok=false
  18. // 查1 - 元素不存在
  19. v1 := m["x"] //
  20. v2, ok2 := m["x"]
  21. fmt.Printf("%#v %#v %#v\n", v1, v2, ok2) // "" "" false
  22. // 查2 - 元素存在
  23. v3 := m["a"]
  24. v4, ok4 := m["a"]
  25. fmt.Printf("%#v %#v %#v\n", v3, v4, ok4) //"va" "va" true
  26. }
  27. // 删, 使用内置函数删除k/v对
  28. {
  29. // delete(m, k) 将k以及k对应的v从m中删掉;如果k不在m中,不执行任何操作
  30. delete(m, "x") // 删除不存在的key,原m不影响
  31. delete(m, "a") // 删除存在的key
  32. fmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"b":"vb", "c":"11"} 2
  33. delete(m, "a") // 重复删除不报错,m无影响
  34. fmt.Printf("%#v %#v\n", m, len(m)) /// map[string]string{"b":"vb", "c":"11"} 2
  35. }

7.5.4 map的遍历

  • 遍历的顺序是随机的
  • 使用for range遍历的时候,k,v使用的同一块内存,这也是容易出现错误的地方

7.5.5 map遍历易错点举例

由于遍历的时候,遍历v使用的同一块地址,同时这块地址是临时分配的。虽然v的地址没有变化,但v的内容在一直变化,当遍历完成后,v的内容是map遍历时最后遍历的元素的值(map遍历无序,每次不确定哪个元素是最后一个元素)。当程序将v的地址放入到slice中的时候,slice在不断地v的地址插入,由于v一直是那块地址,因此slice中的每个元素记录的都是v的地址。因此当打印slice中的内容的时候,都是同一个值