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

相关推荐
小杍随笔2 分钟前
【Rust 语言编程知识与应用:闭包详解】
开发语言·后端·rust
2301_764441338 分钟前
使用python构建的STAR实验ΛΛ̄自旋关联完整仿真
开发语言·python·算法
共享家95279 分钟前
Java入门( 异常 )
java·开发语言·php
御形封灵11 分钟前
基于canvas的路网编辑交互
开发语言·javascript·交互
xifangge202514 分钟前
Python 爬虫实战:爬取豆瓣电影 Top250 数据并进行可视化分析
开发语言·爬虫·python
SunnyDays101115 分钟前
C# 实战:快速查找并高亮 Word 文档中的文字(普通查找 + 正则表达式)
开发语言·c#
kaoshi100app18 分钟前
本周,河南二建报名公布!
开发语言·人工智能·职场和发展·学习方法
421!18 分钟前
ESP32学习笔记之GPIO
开发语言·笔记·单片机·嵌入式硬件·学习·算法·fpga开发
小璐资源网20 分钟前
从源码看ArrayList与LinkedList的性能差异
后端
problc29 分钟前
在 OpenClaw 里一句话记账:消费说出来,账单自动进乖猫记账 App
开发语言·python