概念
映射是一种数据结构,用于存储一系列无序的键值对,它基于键来存储值。
映射的特点是能够基于键快速检索数据。键就像是数组的索引一样,指向与键关联的值。
与 C++、Java 等编程语言不同,在 Golang 中使用映射不需要引入任何库。
因此 Golang 的映射使用起来更加方便。
我们可以通过下图简要的理解一下映射中键值对的关系:
图中的每个键值对表示一种颜色的字符串名称及其对应的十六进制值,其中名称为键,十六进制数为值。
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声明
语法
var mapName map[keyType]valueType
参数
参数 | 描述 |
---|---|
var | 声明变量使用的关键字 |
mapName | 声明的 map 变量的变量名 |
map | 声明 map 变量的关键字 |
keyType | map 的键的类型 |
valueType | map 的值的类型 |
说明
声明一个 变量 名为 mapName, key 为 keyType 类型,value 为 valueType 类型的 map。
lang := map[string]string{
"Vue":"js",
"Gin":"golang",
"SpringBoot":"java",
}
map创建
创建有三种形式,分别为:
- 先定义后使用 make 创建
- 直接使用 make
- 字面量声明映射
make创建
- name: 为 mapName,
- key: 为 keyType 类型,
- value: 为 valueType 类型,
- len: 为 len 的 map。
mapName := make(map[keyType]valueType, len)
package main
import "fmt"
func main() {
//先定义后使用 make 创建一个 map
var mapServer map[string]string
mapServer = make(map[string]string, 3)
mapServer["host"] = "127.0.0.01"
mapServer["port"] = "8080"
fmt.Println("mapServer =", mapServer, "len=", len(mapServer)) // mapServer = map[host:127.0.0.01 port:8080] len= 2
// make创建
mapLang := make(map[string]string, 3)
mapLang["Server"] = "Golang"
mapLang["JavaScript"] = "Vue"
mapLang["Db"] = "MySql"
fmt.Println("mapLang =", mapLang, "len=", len(mapLang)) // mapLang = map[Db:MySql JavaScript:Vue Server:Golang] len= 3
//直接使用 make 创建一个 map
mapLang2 := map[string]string{
"Server":"Golang",
"JavaScript":"Vue",
"Db":"Redis",
}
fmt.Println("mapLang2 =", mapLang2, "len=", len(mapLang2)) // mapLang2 = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
// 字面量创建
mapColor := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
fmt.Println("mapColor =", mapColor, "len=", len(mapColor)) // mapColor = map[Orange:#e95a22 Red:#da1337] len= 2
/**
mapServer = map[host:127.0.0.01 port:8080] len= 2
mapLang = map[Db:MySql JavaScript:Vue Server:Golang] len= 3
mapLang2 = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
mapColor = map[Orange:#e95a22 Red:#da1337] len= 2
*/
}
map遍历
Go 语言 中 map 的遍历只能使用 for range 的形式。
使用 for range 遍历 map,如果我们只使用一个返回参数接受,那么返回的是 map 的 key。
因此 map 是无序的,因此同一个 map,每次遍历获取的结果的顺序很可能是不一致的。
for range 循环遍历map
语法
for key, value := range mapName{ }
package main
import "fmt"
func main() {
mapLang := map[string]string{
"Server":"Golang",
"JavaScript":"Vue",
"Db":"Redis",
}
fmt.Println("mapLang =", mapLang, "len=", len(mapLang))
fmt.Println("--------遍历------")
for key, value := range mapLang {
fmt.Printf("mapLang[%q]=%q \n", key, value)
}
fmt.Println("--------遍历key------")
for key, _ := range mapLang {
fmt.Println(key)
}
fmt.Println("--------遍历value------")
for _, value := range mapLang {
fmt.Println(value)
}
}
mapLang = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
--------遍历------
mapLang["Server"]="Golang"
mapLang["JavaScript"]="Vue"
mapLang["Db"]="Redis"
--------遍历key------
Db
Server
JavaScript
--------遍历value------
Golang
Vue
Redis
获取map元素
value, isOk := mapName[key]
说明
- value: 获取到的值,如果只判断key,value 可以用下划线忽略_
- isOk: 是否获取到值,获取到则返回 true,否则,返回 false
package main
import "fmt"
func main() {
mapLang := map[string]string{
"Server":"Golang",
"JavaScript":"Vue",
"Db":"Redis",
}
if value, isOk := mapLang["Db"]; isOk{
fmt.Printf("mapLang[Db]=%q", value)
}else{
fmt.Println("不存在的key")
}
}
删除map元素
delete(mapName, KEY)
如果 key 不存在,不会报错
package main
import "fmt"
func main() {
mapLang := map[string]string{
"Server":"Golang",
"JavaScript":"Vue",
"Db":"Redis",
}
if value, isOk := mapLang["Db"]; isOk{
fmt.Printf("mapLang[Db]=%q", value)
}else{
fmt.Println("不存在的key")
}
// 不存在 key: Nginx 运行不会报错
delete(mapLang, "Nginx")
fmt.Println("mapLang =", mapLang, "len=", len(mapLang))
// mapLang[Db]="Redis"mapLang = map[Db:Redis JavaScript:Vue Server:Golang] len= 3
delete(mapLang, "Server")
fmt.Println("mapLang =", mapLang, "len=", len(mapLang))
// mapLang = map[Db:Redis JavaScript:Vue] len= 2
}
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
// 添加元素
code.Store("Server", "Golang")
code.Store("JavaScript", "Vue")
code.Store("Db", "Redis")
fmt.Println("code=", code)
// 删除
code.Delete("Server")
code.Delete("Server")
fmt.Println("code=", code)
// 获取
if value, isOK := code.Load("JavaScript"); isOK {
fmt.Println("JavaScript=", value)
} else {
fmt.Println("不存在key")
}
// 不存在front key 则设置
if value, isOK := code.LoadOrStore("front", "React"); isOK {
fmt.Println("front=", value)
} else {
fmt.Println("不存在front key")
}
fmt.Println("code=", code)
// 遍历
code.Range(walk)
}
func walk(key, value interface{}) bool { fmt.Println(“Key =”, key, “Value =”, value)
// return false 终止遍历 只会遍历一个元素
return true
} ```