概念

映射是一种数据结构,用于存储一系列无序的键值对,它基于键来存储值。
映射的特点是能够基于键快速检索数据。键就像是数组的索引一样,指向与键关联的值。

与 C++、Java 等编程语言不同,在 Golang 中使用映射不需要引入任何库。
因此 Golang 的映射使用起来更加方便。

我们可以通过下图简要的理解一下映射中键值对的关系:
映射(map) - 图1
图中的每个键值对表示一种颜色的字符串名称及其对应的十六进制值,其中名称为键,十六进制数为值。

Go map

Golang 中的映射在底层是用哈希表实现的
https://github.com/golang/go/blob/3b2a578166/src/runtime/map.go
]而 C++ 中的映射则是使用红黑树实现的。

Go 语言 中 map 是一个 key(索引)和 value(值)形式的无序的集合,也可以称为关联数组或字典,Golang 中的 map 能够快速根据给定 key,找到对应的 value 的数据结构。

Golang 的 map 的 key 可以是任何可以使用 == 进行比较的 数据类型,比如 int、string、bool 等,value 可以是任意的类型。

map 是一个无序的数据结构,因此同一个 map,每次遍历获取的顺序很可能是不一致的。

map声明

语法

  1. var mapName map[keyType]valueType

参数

参数 描述
var 声明变量使用的关键字
mapName 声明的 map 变量的变量名
map 声明 map 变量的关键字
keyType map 的键的类型
valueType map 的值的类型

说明
声明一个 变量 名为 mapName, key 为 keyType 类型,value 为 valueType 类型的 map。

  1. lang := map[string]string{
  2. "Vue":"js",
  3. "Gin":"golang",
  4. "SpringBoot":"java",
  5. }

map创建

创建有三种形式,分别为:

  • 先定义后使用 make 创建
  • 直接使用 make
  • 字面量声明映射

make创建

  • name: 为 mapName,
  • key: 为 keyType 类型,
  • value: 为 valueType 类型,
  • len: 为 len 的 map。
    1. mapName := make(map[keyType]valueType, len)
  1. package main
  2. import "fmt"
  3. func main() {
  4. //先定义后使用 make 创建一个 map
  5. var mapServer map[string]string
  6. mapServer = make(map[string]string, 3)
  7. mapServer["host"] = "127.0.0.01"
  8. mapServer["port"] = "8080"
  9. fmt.Println("mapServer =", mapServer, "len=", len(mapServer)) // mapServer = map[host:127.0.0.01 port:8080] len= 2
  10. // make创建
  11. mapLang := make(map[string]string, 3)
  12. mapLang["Server"] = "Golang"
  13. mapLang["JavaScript"] = "Vue"
  14. mapLang["Db"] = "MySql"
  15. fmt.Println("mapLang =", mapLang, "len=", len(mapLang)) // mapLang = map[Db:MySql JavaScript:Vue Server:Golang] len= 3
  16. //直接使用 make 创建一个 map
  17. mapLang2 := map[string]string{
  18. "Server":"Golang",
  19. "JavaScript":"Vue",
  20. "Db":"Redis",
  21. }
  22. fmt.Println("mapLang2 =", mapLang2, "len=", len(mapLang2)) // mapLang2 = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
  23. // 字面量创建
  24. mapColor := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
  25. fmt.Println("mapColor =", mapColor, "len=", len(mapColor)) // mapColor = map[Orange:#e95a22 Red:#da1337] len= 2
  26. /**
  27. mapServer = map[host:127.0.0.01 port:8080] len= 2
  28. mapLang = map[Db:MySql JavaScript:Vue Server:Golang] len= 3
  29. mapLang2 = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
  30. mapColor = map[Orange:#e95a22 Red:#da1337] len= 2
  31. */
  32. }

map遍历

Go 语言 中 map 的遍历只能使用 for range 的形式。
使用 for range 遍历 map,如果我们只使用一个返回参数接受,那么返回的是 map 的 key。

因此 map 是无序的,因此同一个 map,每次遍历获取的结果的顺序很可能是不一致的。

for range 循环遍历map
语法

  1. for key, value := range mapName{ }
  1. package main
  2. import "fmt"
  3. func main() {
  4. mapLang := map[string]string{
  5. "Server":"Golang",
  6. "JavaScript":"Vue",
  7. "Db":"Redis",
  8. }
  9. fmt.Println("mapLang =", mapLang, "len=", len(mapLang))
  10. fmt.Println("--------遍历------")
  11. for key, value := range mapLang {
  12. fmt.Printf("mapLang[%q]=%q \n", key, value)
  13. }
  14. fmt.Println("--------遍历key------")
  15. for key, _ := range mapLang {
  16. fmt.Println(key)
  17. }
  18. fmt.Println("--------遍历value------")
  19. for _, value := range mapLang {
  20. fmt.Println(value)
  21. }
  22. }
  23. mapLang = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
  24. --------遍历------
  25. mapLang["Server"]="Golang"
  26. mapLang["JavaScript"]="Vue"
  27. mapLang["Db"]="Redis"
  28. --------遍历key------
  29. Db
  30. Server
  31. JavaScript
  32. --------遍历value------
  33. Golang
  34. Vue
  35. Redis

获取map元素

  1. value, isOk := mapName[key]

说明

  • value: 获取到的值,如果只判断key,value 可以用下划线忽略_
  • isOk: 是否获取到值,获取到则返回 true,否则,返回 false
  1. package main
  2. import "fmt"
  3. func main() {
  4. mapLang := map[string]string{
  5. "Server":"Golang",
  6. "JavaScript":"Vue",
  7. "Db":"Redis",
  8. }
  9. if value, isOk := mapLang["Db"]; isOk{
  10. fmt.Printf("mapLang[Db]=%q", value)
  11. }else{
  12. fmt.Println("不存在的key")
  13. }
  14. }

删除map元素

  1. delete(mapName, KEY)

如果 key 不存在,不会报错

  1. package main
  2. import "fmt"
  3. func main() {
  4. mapLang := map[string]string{
  5. "Server":"Golang",
  6. "JavaScript":"Vue",
  7. "Db":"Redis",
  8. }
  9. if value, isOk := mapLang["Db"]; isOk{
  10. fmt.Printf("mapLang[Db]=%q", value)
  11. }else{
  12. fmt.Println("不存在的key")
  13. }
  14. // 不存在 key: Nginx 运行不会报错
  15. delete(mapLang, "Nginx")
  16. fmt.Println("mapLang =", mapLang, "len=", len(mapLang))
  17. // mapLang[Db]="Redis"mapLang = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
  18. delete(mapLang, "Server")
  19. fmt.Println("mapLang =", mapLang, "len=", len(mapLang))
  20. // mapLang = map[Db:Redis JavaScript:Vue] len= 2
  21. }

syncMap

线程安全

  • map 如果在并发读的情况下是线程安全的,如果是在并发写的情况下,则是线程不安全的。
  • sync.Map 是并发写安全的

数据类型

  • map 的 key 和 value 的 类型 必须是一致的
  • sync.Map 的 key 和 value 不一定是要相同的类型,不同的类型也是支持的

sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用。

  • Store 表示存储
  • Load 表示获取
  • Delete 表示删除
  • LoadOrStore 存在返回key对应元素,不存在设置元素 ```go package main

import ( “fmt” “sync” )

func main() { //使用 sync.Map Delete 删除不存在的元素,不会报错 var code sync.Map

  1. // 添加元素
  2. code.Store("Server", "Golang")
  3. code.Store("JavaScript", "Vue")
  4. code.Store("Db", "Redis")
  5. fmt.Println("code=", code)
  6. // 删除
  7. code.Delete("Server")
  8. code.Delete("Server")
  9. fmt.Println("code=", code)
  10. // 获取
  11. if value, isOK := code.Load("JavaScript"); isOK {
  12. fmt.Println("JavaScript=", value)
  13. } else {
  14. fmt.Println("不存在key")
  15. }
  16. // 不存在front key 则设置
  17. if value, isOK := code.LoadOrStore("front", "React"); isOK {
  18. fmt.Println("front=", value)
  19. } else {
  20. fmt.Println("不存在front key")
  21. }
  22. fmt.Println("code=", code)
  23. // 遍历
  24. code.Range(walk)

}

func walk(key, value interface{}) bool { fmt.Println(“Key =”, key, “Value =”, value)

  1. // return false 终止遍历 只会遍历一个元素
  2. return true

} ```