声明和初始化 Map#
map 是一种特殊的数据结构,通过键 key 和值 value 来保存数据,可以快速地根据 key 找到其对应的 value,与 python 中的字典和 Java 中的 HashMap 类似。
map 是引用类型,声明方式如下:
var variable map[keyType]valueType
在声明的时候不需要知道 map 的长度,map 是可以动态增长的。
未初始化的 map 的值是 nil。
map 中的 key 只能是可以用 == 和 != 来比较的变量类型,例如 string,int 和 float 等,不能是数组,结构体和切片,但指针和接口可以作为 key。如果要使用结构体来作为 key,需要提供 Key() 和 Hash() 方法,value 可以为任意类型。
可以通过赋值符号来设置 key1 对应的 value:
map1[key1] = value
也可以根据赋值符号获取 key1 对应的 value,若 map1 中没有 key1 对应的值,val 将会被赋值 map1 的值类型的空值。
val := map1[key1]
示例:
package main
import "fmt"
func main() {
var mapLit map[string]int
var mapAssigned map[string]int
mapLit = map[string]int{"one": 1, "two": 2}
mapCreated := make(map[string]float32)
mapAssigned = mapLit
mapCreated["key1"] = 4.5
mapCreated["key2"] = 3.14159
mapAssigned["two"] = 3
fmt.Printf("Map literal at \"one\" is: %d\n", mapLit["one"])
fmt.Printf("Map created at \"key2\" is: %f\n", mapCreated["key2"])
fmt.Printf("Map assigned at \"two\" is: %d\n", mapLit["two"])
fmt.Printf("Map literal at \"ten\" is: %d\n", mapLit["ten"])
}
上述代码运行结果为:
Map literal at "one" is: 1
Map created at "key2" is: 3.14159
Map assigned at "two" is: 3
Mpa literal at "ten" is: 0
可以用 {key1: val1, key2: val2} 来初始化 map。
map 是引用类型,因此用 make 来分配内存。
map 的常规初始化方式:
var map1[keyType]valueType = make(map[keyType]valueType)
也可以简写为:
map1 := make(map[keyType]valueType)
mapCreated := make(map[string]float) 相当于:mapCreated := map[string]float{}。
Map 容量#
map 会动态扩容,因此它不存在长度限制。但也可以在初始化 map 时指定它的初始容量,格式如下:
map1 := make(map[string]int, 100) // map1 的初始容量为 100
当 map 增长到最大容量时,容量会自动加 1。但对于性能要求较高的场景,若 map 中保存的数据较多或易快速扩张,建议在初始化时指定其初始容量。
判断键值对是否存在#
我们可以通过如下的格式来判断 map 中的 key 是否存在:
val, ok := map1[key]
若 ok 的值为 true,则表明该 key 存在,否则不存在。
若只是想判断 key 是否存在,而不需要获取 key 对应的 value,可以这样写:
_, ok := map1[key]
还可以和 if 混用:
if _, ok := map1[key]; ok {
// ...
}
删除元素#
删除 map 中的元素,可以通过 delete 函数,如删除 map1 中 key 对应的元素:
delete(map1, key)
即使要删除的 key 不存在,也不会报错。
遍历 Map#
可以通过 for range 循环来遍历 map:
for key, value := range map1 {
// ...
}
如果只需遍历 map 中的 value,可以用匿名变量来接收 key:
for _, value := range map1 {
// ...
}
如果只需要遍历 map 的 key,可以省略 value:
for key := range map1 {
// ...
}
我们来看一个例子:
package main
import "fmt"
func main() {
map1 := make(map[int]float32)
map1[1] = 1.0
map1[2] = 2.0
map1[3] = 3.0
map1[4] = 4.0
for key, value := range map1 {
fmt.Printf("key is: %d - value is: %f\n", key, value)
}
}
上述代码运行结果为:
key is: 3 - value is: 3.000000
key is: 1 - value is: 1.000000
key is: 4 - value is: 4.000000
key is: 2 - value is: 2.000000
注意:
map中元素不是按照key来排序的。
Map 类型的切片#
如果我们要创建一个 map 类型的切片,一定要使用两次 make() 函数,第一次分配切片的内存,第二次分配 map 的内存。
来看一个例子:
package main
import "fmt"
func main() {
// Version A:
items := make([]map[int]int, 5)
for i:= range items {
items[i] = make(map[int]int, 1)
items[i][1] = 2
}
fmt.Printf("Version A: Value of items: %v\n", items)
// Version B: NOT GOOD!
items2 := make([]map[int]int, 5)
for _, item := range items2 {
item = make(map[int]int, 1) // item 仅仅是切片 items2 元素的拷贝
item[1] = 2
}
fmt.Printf("Version B: Value of items: %v\n", items2)
}
运行结果为:
Version A: Value of items: [map[1:2] map[1:2] map[1:2] map[1:2] map[1:2]]
Version B: Value of items: [map[] map[] map[] map[] map[]]