7-map¶
Note
map 是 Go 提供的一种映射关系容器,其内部使用散列表(hash)
实现
map 是一种无序的基于 key-value
的数据结构
Go 中的 map 是引用类型,必须初始化才能使用。
- key 可以是任意可用
== 或 !=
比较的类型,如:string、int、float - 数组、切片不能作为 key
- 指针和接口类型可以作为 key
- 包含数组切片的结构体不能作为 key,只包含原生类型的结构体可以作为 key
- value 可以是任意类型
- 通过 key 在map 中查找是很快的,但是还是比数组和切片慢100倍。如果性能很重要的话还是用切片来解决问题。
- 如果结构体要作为 key 可以提供
Key()
和Hash()
方法 - map可以用函数作为值,这样就可以用来做分支结构:用key来选择要执行的函数。
注意
map 是引用类型!!!
声明¶
定义语法如下
声明时不需要直到map长度,map是可以动态增长的
未初始化的map的值是 nil,需要使用 make()
函数来分配内存
cap
是可选的,但是我们应该在初始化map的时候就为其指定一个合适的容量。
Example
声明并初始化¶
func main() {
m1 := map[int]string{
1: "Alice",
2: "Boii",
3: "Candy",
4: "Danish",
}
fmt.Println(m1) // map[1:Alice 2:Boii 3:Candy 4:Danish]
fmt.Printf("%T \n", m1) // map[int]string
}
Warning
这种方式,每一对 k-v
后面都要有,
,最后一对也要有
单独赋值¶
func main() {
m1 := make(map[int]string)
m1[1] = "Alice"
m1[2] = "Boii"
m1[5] = "Eva"
fmt.Println(m1) // map[1:Alice 2:Boii 5:Eva]
}
判断键是否存在¶
Go 中有个判断 map 中键是否存在的特殊写法,基本格式为:
Example
遍历¶
可以使用 for...range
遍历
func main() {
m1 := map[byte]string{
'a': "Alice",
'b': "Boii",
'c': "Candy",
'd': "Danish",
}
for k, v := range m1 {
fmt.Println(k, v)
}
}
只想遍历 key 的时候可以
只想遍历 value 的时候可以
Tip
遍历 map 时元素顺序与添加键值对顺序无关。官方的说法是无关,但是有人专门去试了以后发现其实是有关的,然后官方就在下一版本中故意打乱顺序了。
delete()¶
Go 的内建函数 delete()
可以从 map 中删除一对键值对,格式如下:
Example
值为切片的map¶
map 中 value 可以是任何类型,所以也可以是切片类型
[]T
:某种类型的切片
Example
func main() {
// 创建一个map, key 为 string, value 为 []int,容量为5
sliceMap1 := make(map[string][]int, 5)
// var sliceMap1 map[string][]int 用这种声明方式也行
// 为 map 中每一对 k-v 初始化
sliceMap1["A"] = make([]int, 3, 3)
sliceMap1["B"] = make([]int, 3, 3)
sliceMap1["C"] = make([]int, 3, 3)
sliceMap1["D"] = make([]int, 3, 3)
sliceMap1["E"] = make([]int, 3, 3)
fmt.Println("1: ",sliceMap1) // 1: map[A:[0 0 0] B:[0 0 0] C:[0 0 0] D:[0 0 0] E:[0 0 0]]
for k, v := range sliceMap1 {
fmt.Println(k, v)
}
// A [0 0 0]
// B [0 0 0]
// C [0 0 0]
// D [0 0 0]
// E [0 0 0]
// 用这种方式初始化效果一样
sliceMap2 := map[string][]int{
"A": {1, 2, 3},
"B": make([]int, 3),
"C": {2, 4, 0, 9},
"D": make([]int, 3),
"E": make([]int, 3),
}
fmt.Println("2: ",sliceMap2) // 2: map[A:[1 2 3] B:[0 0 0] C:[2 4 0 9] D:[0 0 0] E:[0 0 0]]
for k, v := range sliceMap2 {
fmt.Println(k, v)
}
// A [1 2 3]
// B [0 0 0]
// C [2 4 0 9]
// D [0 0 0]
// E [0 0 0]
}
值为map的切片¶
看起来好像有点绕,但是捋清楚就好办了
map[keyT]valT
是map类型,[]T
是切片类型,那么[]map[keyT]valT
就是map类型切片了
// 类型定义
[]map[keyT]valT
// 声明
var idn []map[keyT]valT
// 声明并初始化
var idn = []map[keyT]valT{
{map1key1: val, map1key2: val, map1key3: val},
{map2key1: val, map2key2: val, map2key3: val},
{map3key1: val, map3key2: val, map3key3: val},
}
// 声明并初始化
idn := []map[keyT]valT{
{map1key1: val, map1key2: val, map1key3: val},
{map2key1: val, map2key2: val, map2key3: val},
{map3key1: val, map3key2: val, map3key3: val},
}
// 使用make
idn := make([]map[keyT]valT, cap)
idn[skey] = make(map[keyT]valT)
idn[skey][mkey] = val
idn[skey] = map[keyT]valT{mkey1: val, mkey2: val}
Example
func main() {
// 声明一个切片,map[int]string 类型的,并初始化
ms := []map[int]string{
{1: "A", 2: "B", 3: "C"},
{4: "I", 6: "N", 9: "G"},
{3: "R", 7: "Y", 5: "Q"},
make(map[int]string),
}
for _, v := range ms {
fmt.Println(v)
}
// map[1:A 2:B 3:C]
// map[4:I 6:N 9:G]
// map[3:R 5:Q 7:Y]
// map[]
}
func main() {
// make 一个切片,类型为 map[int]string, 长度和容量都为 3
mapSlice := make([]map[int]string, 3)
// 为切片第一个元素创建一个 map,然后为其逐个添加 k-v
mapSlice[0] = make(map[int]string)
mapSlice[0][1] = "A"
mapSlice[0][2] = "B"
mapSlice[0][3] = "C"
// 为切片第二个元素 创建并初始化一个 map
mapSlice[1] = map[int]string{4: "I", 6: "N", 9: "G"}
for _, v := range mapSlice {
fmt.Println(v)
}
// map[1:A 2:B 3:C]
// map[4:I 6:N 9:G]
// map[]
}
Danger
- Go 内置的 map 不是并发安全的,并发安全的 map 可以使用标准包 sync 中的 map
- 不要直接修改 map value 中某个成员的值。如果想修改 map value 中的某个成员的值,必须整体赋值。
eg:
练习¶
- 写一个程序,统计一个字符串中每个单词出现的次数。比如:”how do you do” 中 how=1 do=2 you=1。
思路:
先用 strings.Split
把单词切割出来
然后利用 map ,把单词作为 key,出现频次作为 value,遍历一下就能得到答案
package main
import (
"fmt"
"strings"
)
func main() {
str := "how do you do I do not know how to tell you"
strSplit := strings.Split(str, " ")
strMap := make(map[string]int)
for _, word := range strSplit {
strMap[word] += 1
}
fmt.Println(strMap)
}
// -----------------------------------------
// Output:
map[I:1 do:3 how:2 know:1 not:1 tell:1 to:1 you:2]