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

相关推荐
HDO清风6 分钟前
CASIA-HWDB2.x 数据集DGRL文件解析(python)
开发语言·人工智能·pytorch·python·目标检测·计算机视觉·restful
2201_756989096 分钟前
C++中的事件驱动编程
开发语言·c++·算法
多米Domi01117 分钟前
0x3f 第48天 面向实习的八股背诵第五天 + 堆一题 背了JUC的题,java.util.Concurrency
开发语言·数据结构·python·算法·leetcode·面试
2301_8223776518 分钟前
模板元编程调试方法
开发语言·c++·算法
csbysj202021 分钟前
Python 循环嵌套
开发语言
测试_AI_一辰24 分钟前
Agent & RAG 测试工程05:把 RAG 的检索过程跑清楚:chunk 是什么、怎么来的、怎么被命中的
开发语言·人工智能·功能测试·自动化·ai编程
Coding茶水间26 分钟前
基于深度学习的输电电力设备检测系统演示与介绍(YOLOv12/v11/v8/v5模型+Pyqt5界面+训练代码+数据集)
开发语言·人工智能·深度学习·yolo·目标检测·机器学习
清风~徐~来31 分钟前
【视频点播系统】BRpc 介绍及使用
开发语言
啟明起鸣32 分钟前
【C++ 性能提升技巧】C++ 的引用、值类型、构造函数、移动语义与 noexcept 特性,可扩容的容器
开发语言·c++