文章目录
- Map
- :one: 使用`Map`
- :star2: 声明和初始化
- :star2: `map`容量
- :star2: 用切片作为`map`的值
- :two: 测试键值对是否存在及删除元素
- :three: `For`-`range`
- :four: `map`类型的切片
- :five: map的排序
- :six:将map的健和值对调
📦 使用版本为1.21.5
Map
在很多编程语言中都有map
的存在,在Python
中叫做字典,在java
中也叫map
,它的存储形式是key-value
1️⃣ 使用Map
🌟 声明和初始化
⭐️ map
是引用类型,可以使用如下方法来声明一个map
,注意只是声明一个map
,而不是初始化
可以使用make
来分配内存,不要使用new
如果你错误的使用 new() 分配了一个引用对象,你会获得一个空引用的指针,相当于声明了一个未初始化的变量并且取了它的地址
func main() {var map1 map[string]int //声明一个map,基础方法 其中string为key的类型,int为value的类型map2 := make(map[string]int) //使用make这里是初始化map了map3 := map[string]int{"one":1,"two":2}
}
- 在声明的时候不需要知道
map
的长度,它也是动态增长的 - 未初始化的
map
的值是nil
key
可以是任意能使用==或者!=操作符比较的类型(string
,int
,float
),数组和切片、结构体不可以作为key,但是接口和指针类型可以(后面会学),如果需要用结构体来作为key
,可以使用Key()
和Hash()
方法通过计算结构体的域来计算出唯一的数字或者字符串的key
(后面会学)value
可以是任意类型的,可以使用空接口类(后面会学),可以存储任意值,但是使用这种类型作为值时需要先做一次类型断言(后面会学)
map 传递给函数的代价很小:在 32 位机器上占 4 个字节,64 位机器上占 8 个字节,无论实际上存储了
多少数据。通过 key 在 map 中寻找值是很快的,比线性查找快得多,但是仍然比从数组和切片的索引中
直接读取要慢 100 倍;所以如果你很在乎性能的话还是建议用切片来解决问题
⭐️ map
可以用函数作为value
,这里就可以用来做分支结构,直接调用value
对应的key
来调用此函数
func main() {map1 := map[string]func() int{"one": func() int {return 1},"two": func() int {return 2},"three": func() int {return 3},}fmt.Println(map1) //输出的是地址
}map[one:0xe33c60 three:0xe33ca0 two:0xe33c80]//或者是
func main() {map1 := map[string]func(i int) int{"one": func(i int) int {return i},"two": func(i int) int {return i},"three": func(i int) int {return i},}fmt.Println(map1["one"](4)) //输出4
}
⭐️ 调用value
的方法和数组类似,直接就是map名[key名]
就好了,
func main() {map1 := map[string]int{"one": 1, "two": 2} //声明一个map,基础方法 其中string为key的类型,int为value的类型map1["three"] = 3 //将map1的可以three的值改为3,如果没有这个key则添加test := map1["two"] //将指定key的赋予给test,如果key类型不存在则会被赋值为map1类型的空值fmt.Print(map1["one"], map1["two"], map1["three"], test)
}//输出
1 2 3 2
⭐️ 如果想要删除键值对,直接使用delete
即可
map1 := map[string]int{"one": 1, "four": 4, "five": 5, "three": 3, "two": 2}delete(map1, "four")
🌟 map
容量
⭐️ map
可以根据新增的key
-value
来动态的伸缩,因此它不存在固定长度或者最大限制,但是在初始化的时候可以选择表面map
的初始容量
func main() {map1 := make(map[string]int,100) //在切片中使用make是一样的
}
当
map
增长到容量上限的时候,如果再增加新的key-value
对,map
的大小会自动加1
。所以出于性能
的考虑,对于大的map
或者会快速扩张的map
,即使只是大概知道容量,也最好先标明
🌟 用切片作为map
的值
⭐️ 既然一个 key
只能对应一个 value
,而 value
又是一个原始类型,那么如果一个 key
要对应多个值怎么
办?例如,当我们要处理unix
机器上的所有进程,以父进程(pid
为整形)作为 key
,所有的子进程(以
所有子进程的 pid
组成的切片)作为 value
。通过将 value
定义为 []int
类型或者其他类型的切片,就可
以优雅的解决这个问题
func main() {map1 := make(map[int][]int)
}
2️⃣ 测试键值对是否存在及删除元素
⭐️ 在获取一个键值对时,就算哪个键不存在,也会返回一个value
所属类型的空值,不好判断这个key
是否存在,可以使用下面这种方法来判断是否存在
test
返回一个 bool
值:如果 two
存在于 map1
,two
就是 two
对应的 value
值,并且
test
为true
;如果 two
不存在,va
就是一个空值,并且 test
会返回 false
func main() {var va intvar test boolmap1 := make(map[string]int)map1["one"] = 1int, test = map1["tow"] println(test, va)
}
3️⃣ For
-range
⭐️ 和数组切片一样,但是map
不是按照 key
的顺序排列的,也不是按照 value
的序排列的
func main() {map1 := make(map[string]int)map1["one"] = 1map1["two"] = 2map1["three"] = 3for key, value := range map1 {println("Key: ", key, "Value: ", value)}
}//第一次输出
Key: one Value: 1
Key: two Value: 2
Key: three Value: 3
//第二次输出
Key: three Value: 3
Key: one Value: 1
Key: two Value: 2
4️⃣ map
类型的切片
⭐️ 想获取一个 map
类型的切片,我们必须使用两次 make()
函数,第一次分配切片,第二次分配
切片中每个 map
元素
func main() {map1 := make([]map[string]int, 5) //分配切片for i := range map1 {map1[i] = make(map[string]int, 1) //分配切片中的每个map元素map1[i]["a"] = i}fmt.Print(map1)
}
⚠️ 错误方法
func main() {map1 := make([]map[string]int, 5)for _, test := range map1 {test = make(map[string]int, 1) //这里只是获取map的一个拷贝,并不是修改maptest["a"] = 2}fmt.Print(map1)
}
//输出
[map[] map[] map[] map[] map[]]
5️⃣ map的排序
⭐️ map
是无序的,如果你想为 map
排序,需要将 key
(或者 value
)拷贝到一个切片,再对切片排序(使用 sort
包,然后可以使用切片的 for-range
方法打印出所有的 key
和 value
func main() {map1 := map[string]int{"one": 1, "four": 4, "five": 5, "three": 3, "two": 2}delete(map1, "four")test := make([]string, len(map1)) //创建一个切片,长度为map1的长度var i int //i为切片的索引for key, _ := range map1 { //读取map的key值,存入对应索引的test切片test[i] = keyi++}sort.Strings(test) //使用sort排序切片for _, key := range test { //去读按照切片内的值fmt.Printf("Key:%v,Value: %v ", key, map1[key])}
}//输出:
Key:five,Value: 5 Key:one,Value: 1 Key:three,Value: 3 Key:two,Value: 2
6️⃣将map的健和值对调
⭐️ 很难直接对map
使用键和值对调,因为可能是键和值的类型不一样,
func main() {map1 := map[string]int{"one": 1, "four": 4, "five": 5, "three": 3, "two": 2} //初始mapmap2 := make(map[int]string, len(map1)) //键值对调后的mapfor k, v := range map1 {map2[v] = k}fmt.Println(map2)
}