Go语言的map

一、map 是什么?

map 是 Go 里 键值对(key-value) 的集合,类似:

  • Java 的 HashMap

  • Python 的 dict

Go 复制代码
map[KeyType]ValueType

特点:

无序、引用类型、key 唯一、查找快

二、map 的基本使用

1. 声明 & 初始化

Go 复制代码
// 声明但未初始化(nil map)
var m map[string]int

// 初始化(推荐)
m = make(map[string]int)

// 声明 + 初始化
m := make(map[string]int)

// 带初始值
m := map[string]int{
    "java":  8,
    "go":    3,
    "python": 5,
}

注意:下面的写法会报错:

Go 复制代码
var m map[string]int
m["a"] = 1   // ❌ panic:assignment to entry in nil map

map 用之前 必须 make 或字面量初始化

2. map的读 / 写 / 删

Go 复制代码
m["go"] = 10          // 写
v := m["go"]          // 读
delete(m, "redis")    // 删除

3. 判断 key 是否存在

Go 复制代码
v, ok := m["python"]
if ok {
    fmt.Println("存在", v)
} else {
    fmt.Println("不存在")
}

如果 key 不存在:

  • vvalue 类型的零值

  • ok == false

三、map 的遍历

Go 复制代码
for k, v := range m {
    fmt.Println(k, v)
}

注意

  • 遍历顺序 每次都可能不一样

  • Go 故意打乱顺序,避免依赖顺序写代码

如果需要顺序:

单独维护一个 slice 存 key

四、map 的 key / value 有哪些限制?

1. key 必须是 可比较类型

以下可以用作key:

  • int

  • string

  • bool

  • 指针

  • 数组

  • struct(前提:字段都可比较)

以下 不可以用作key:

  • slice

  • map

  • function

2 value 没限制

Go 复制代码
map[string][]int
map[string]map[string]int
map[string]interface{}

五、map 是引用类型

Go 复制代码
func modify(m map[string]int) {
    m["go"] = 100
}

func main() {
    m := map[string]int{"go": 10}
    modify(m)
    fmt.Println(m["go"]) // 100
}

将map作为参数传入map,vaule不会发生改变,是因为:

  • map 底层是 指针结构

  • 函数传参不会拷贝整个 map

六、并发安全问题

map 不是并发安全的,使用不当会报以下错误:

fatal error: concurrent map writes

可以使用以下方式来实现并发安全

1.加锁(最常用)

Go 复制代码
var m = make(map[string]int)
var mu sync.Mutex

mu.Lock()
m["a"] = 1
mu.Unlock()
  1. 使用 sync.Map(读多写少)
Go 复制代码
var m sync.Map
m.Store("a", 1)
v, ok := m.Load("a")

3.channel 串行化访问

七、map 的一些常见坑

  1. 不能直接取地址
Go 复制代码
v := m["go"]
// &m["go"]  不允许

因为 map 在扩容时,地址会变化

  1. 不能比较 map
Go 复制代码
m1 == m2   //  编译错误

只能和 nil 比较:

Go 复制代码
if m == nil {}

3. map 扩容会导致性能抖动

可以提前分配容量:

Go 复制代码
m := make(map[string]int, 10000)

八、和 Java HashMap 的对比

维度 Go map Java HashMap
是否有序 ❌ 无序 ❌ 无序
是否线程安全
初始化 make / 字面量 new HashMap
判断存在 v, ok := m[k] containsKey()
nil 行为 写会 panic put 会 NPE
泛型 原生支持 Java 8+

九、典型使用场景

  • 缓存 / 去重

  • 计数器(词频统计)

  • ID → 对象 映射

  • 配置表

  • JSON 反序列化动态字段

Go 复制代码
count := make(map[string]int)
for _, w := range words {
    count[w]++
}

十、总结

Go 的 map = 高性能、语法极简,但对并发和顺序非常"严格"的 HashMap

相关推荐
hudawei9961 小时前
kotlin冷流热流的区别
android·开发语言·kotlin·flow··冷流·热流
小信啊啊1 小时前
Go语言数组
开发语言·后端·golang
白宇横流学长1 小时前
基于SpringBoot实现的零食销售商城设计与实现【源码+文档】
java·spring boot·后端
qq_336313931 小时前
Java基础-Stream流
java·开发语言·windows
superman超哥1 小时前
仓颉语言中异常捕获机制的深度剖析与工程实践
c语言·开发语言·后端·python·仓颉
再__努力1点1 小时前
【76】Haar特征的Adaboost级联人脸检测全解析及python实现
开发语言·图像处理·人工智能·python·算法·计算机视觉·人脸检测
驱动探索者2 小时前
[缩略语大全]之[INTEL]篇
java·后端·spring·intel
one9962 小时前
C# 的进程间通信(IPC,Inter-Process Communication)
开发语言·c#
Victor3562 小时前
Netty(21)Netty的SSL/TLS支持是如何实现的?
后端