Golang复习笔记之map(面向面试)

声明:文中文字为原创+整理,图片来源于网络,只供自己复习,无任何侵权/盗取目的,如有请找我删除进行维权。

介绍:

map 是一种内置的数据类型,用于存储键值对(key-value pairs)。它提供了高效的键值对查找、插入和删除操作。map 可以看作是一种哈希表,键是唯一的,值可以是任意类型。其中,KeyType 是键的类型;ValueType 是值的类型,值可以是任意类型。

map[KeyType]ValueType

操作:

持插入、更新、访问、删除键值对,以及遍历 map。

创建map:
m := make(map[string]int)
插入:

m["banana"] = 7 // 插入新的键值对
m["apple"] = 6 // 更新已有键的值

键值类型:

  • map 中的键是唯一的,插入相同的键会覆盖之前的值。
  • map 的键类型必须是可比较的类型,能进行 == 和 != 运算;不允许使用切片(slice)、函数等不可比较的类型作为键。常见可作为键的类型包括:int、float、string、struct、pointer 等。
  • 不可作为键的类型包括:slicemapfunction,因为这些类型在 Go 中是不可比较的。

底层实现:

map 底层使用哈希表(hash table)实现,键通过哈希函数被映射到哈希表中的一个槽位。
哈希冲突采用开放寻址或链地址法来解决(Go 语言使用的是链地址法,将冲突的键存储在相同的桶中。)在链地址法中,每个桶bucket存储的是一个链表或数组,当多个键的哈希值相同时,这些键会被存储在同一个桶中。桶是一种存储一组键值对的结构,且 map 在负载因子超过一定阈值时,会触发自动扩容。

扩容:

  • map 的扩容是通过重新分配更大的内存空间来完成的。
  • map 在负载因子超过一定阈值时,会触发自动扩容。
  • 每次扩容会使容量增加为原来的两倍,所有键值对会被重新哈希分配到新的桶中。扩容过程涉及大量的内存分配和数据迁移,性能开销较大。因此,在频繁插入或删除大量数据时,可能会影响程序的性能。

并发安全:

  • Go 中的原生 map 不是并发安全的,在多线程环境中同时读写 map 会导致数据竞态。
  • 使用 sync.Mutexsync.RWMutex 来对 map 进行读写加锁,以确保线程安全。
  • Go 1.9 之后引入了 sync.Map,它是一种并发安全的 map,适用于读多写少的场景。

垃圾回收:

  • Go 中的 map 和其他变量一样受垃圾回收机制的管理。当键值对被删除后,键值对应的内存将被标记为可回收。
  • 如果频繁插入和删除键值对,可能会导致碎片化和内存占用增大,建议定期将 map 重新分配(通过重新创建 map 并复制数据)。

性能优化:

  • 使用 make 函数预分配 map 的容量,避免频繁扩容带来的性能开销。m := make(map[string]int)
    选择合适的键类型,尽量使用简单的类型作为键,如 int、string,避免复杂结构。
    在并发场景下,使用 sync.Map 或手动加锁来确保安全和高效的访问,确保 map 中的键顺序一致

零值与nil

  • map 的零值是 nil,nil map 不能存储任何键值对,进行读取操作不会引发错误,写入操作会导致运行时错误。
  • 空 map 是已分配内存但没有存储任何键值对的 map,可以正常进行读写操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值