3.3.1 map的声明与初始化
什么是map?
Go语言中的map是一种无序的键值对集合,类似于其他语言中的字典或哈希表。map的键必须是可比较的类型,比如字符串、整数等。值可以是任意类型。
Go 语言 map 的底层实现
Go 语言中的 map 底层实现是一个哈希表。哈希表是一种通过哈希函数将值映射到特定的索引位置的数据结构,从而实现快速查找。Go 的 map 实现经过了精心的设计,具有高效的性能和良好的并发安全性。
hmap 结构体
Go map 的底层数据结构是 hmap 结构体。这个结构体包含了 map 的所有元数据,包括:
- 计数器: 记录 map 中的元素个数、扩容次数等。
- 桶数组: 一个指向桶数组的指针。每个桶存储多个键值对。
- 溢出桶: 当桶中的元素过多时,会将多余的元素放到溢出桶中。
- 加载因子: 用于判断是否需要扩容。
- 哈希种子: 用于计算哈希值。
工作原理
- 哈希计算: 当向 map 中插入一个键值对时,首先会根据键的哈希值计算出该键应该存储在哪个桶中。
- 桶内查找: 在指定的桶中,通过比较键的哈希值和相等性来查找对应的键值对。如果找到,则更新值;否则,插入新的键值对。
- 扩容: 当 map 中的元素数量超过了某个阈值时,会触发扩容操作。扩容过程会创建一个新的、更大的桶数组,并将旧桶数组中的元素重新散列到新桶数组中。
核心概念
- 桶 (bucket): map 的底层存储单元,每个桶可以存储多个键值对。
- 溢出桶: 当桶中的元素过多时,会将多余的元素放到溢出桶中,以避免单个桶过大。
- 加载因子: 用于判断 map 是否需要扩容。当元素数量超过加载因子乘以桶数量时,就会触发扩容。
- 哈希冲突: 当两个不同的键计算出相同的哈希值时,就会发生哈希冲突。Go map 使用开放寻址法来解决哈希冲突,即在同一个桶中线性探测下一个空闲位置。
优点
- 高效: 哈希表的查找、插入和删除操作的时间复杂度通常为 O(1)。
- 灵活: 可以存储任意类型的键值对。
- 并发安全: Go 的 map 在多协程并发访问时是安全的。
map的声明与初始化
- 声明一个map
var myMap map[string]int
map[string]int
: 表示这是一个键为字符串,值为整型的map。
- 初始化一个map
- 使用make函数:
myMap := make(map[string]int)
make
函数用来分配内存并初始化map。
- 初始化并赋值:
myMap := map[string]int{
"apple": 5, "banana": 3}
直接在声明时初始化并赋值。
map的常用操作
- 添加元素:
map[key] = value
- 访问元素:
value := map[key]
- 判断key是否存在:
value, ok := map[key]
- 删除元素:
delete(map, key)
- 遍历map: 使用 for range 循环。
3.3.2 添加、删除与更新键值对
1. 添加键值对
在 Go 语言中,向 map 添加键值对非常直观:
package main
import "fmt"
func main() {
// 创建一个空的字符串到整型的 map
myMap := make(map[string]int)
// 添加键值对
myMap["apple"] = 5
myMap[