当前位置: 首页 > article >正文

Go 语言 `map` 详解

Go 语言 map 详解

1. 什么是 map

在 Go 语言中,map 是一种 键值对(key-value) 数据结构,类似于 Python 的 dict 或 Java 的 HashMap。它提供了高效的查找、插入和删除操作。

2. map 的声明与初始化

在 Go 中,可以使用 make() 或直接字面量方式创建 map

方式 1:使用 make()
m := make(map[string]int) // 创建一个键类型为 string,值类型为 int 的 map
方式 2:使用字面量
m := map[string]int{
    "apple":  5,
    "banana": 10,
}
方式 3:创建空 map
var m map[string]int // 此时 m 为空指针,不能直接赋值
m = make(map[string]int) // 需要初始化

3. 基本操作

添加或更新元素
m["apple"] = 8
m["banana"] = 12
获取元素
val := m["apple"]
fmt.Println(val) // 8
删除元素
delete(m, "banana") // 删除 key 为 "banana" 的元素
检查 key 是否存在

map 访问时如果 key 不存在,返回零值,可以使用双返回值来判断:

val, exists := m["banana"]
if exists {
    fmt.Println("banana 的值是", val)
} else {
    fmt.Println("banana 不存在")
}

4. 遍历 map

使用 for range 遍历 map

for key, value := range m {
    fmt.Println("Key:", key, "Value:", value)
}

如果只需要 key

for key := range m {
    fmt.Println("Key:", key)
}

5. map 不能作为函数参数传递值类型

在 Go 中,map 是引用类型,传递给函数时不会复制整个 map,而是传递引用。

func modify(m map[string]int) {
    m["orange"] = 20
}

func main() {
    m := make(map[string]int)
    modify(m)
    fmt.Println(m) // map[orange:20]
}

6. map 的并发安全问题

map 不是线程安全的,多个 goroutine 并发写 map 时会导致 fatal error: concurrent map writes

解决方案:

  • 使用 sync.Mutex 保护 map
    var mu sync.Mutex
    m := make(map[string]int)
    
    go func() {
        mu.Lock()
        m["apple"] = 10
        mu.Unlock()
    }()
    
  • 使用 sync.Map(Go 1.9+)
    var m sync.Map
    m.Store("apple", 10)         // 写入
    val, ok := m.Load("apple")   // 读取
    fmt.Println(val, ok)
    

7. map 的长度与清空

获取 map 长度
fmt.Println(len(m)) // 获取 map 中键值对的数量
清空 map

Go 没有直接清空 map 的方法,可以通过重新 make() 一个新 map

m = make(map[string]int) // 清空 map

8. map 的键类型限制

mapkey 必须是可比较类型,即支持 ==!= 运算符,如:
✅ 允许:string, int, float, bool, struct
❌ 不允许:slice, map, function

示例:

// 正确
m := map[int]string{1: "one", 2: "two"}

// 错误(切片不可作为 map key)
m := map[[]int]string{} // 编译错误

如果需要使用 slice 作为 key,可以转换为字符串:

import "fmt"

func main() {
    m := make(map[string]int)
    key := fmt.Sprintf("%v", []int{1, 2, 3})
    m[key] = 10
    fmt.Println(m)
}

9. map 的值类型

map 的值类型可以是任何类型,包括 map 本身:

nestedMap := map[string]map[string]int{
    "fruits": {
        "apple":  5,
        "banana": 8,
    },
}
fmt.Println(nestedMap["fruits"]["apple"]) // 5

10. map 的排序

map 默认是无序的,可以手动排序:

import "sort"

keys := make([]string, 0, len(m))
for key := range m {
    keys = append(keys, key)
}
sort.Strings(keys) // 排序 keys

for _, key := range keys {
    fmt.Println("Key:", key, "Value:", m[key])
}

总结

  • map 是 Go 的键值对数据结构,查找、删除、插入都很高效(O(1))。
  • map 需要用 make() 或字面量方式初始化,未初始化的 map 不能写入数据。
  • 读取 map 时如果 key 不存在,会返回值类型的零值,判断存在性用 val, ok := m[key]
  • map 不是线程安全的,需要 sync.Mutexsync.Map 进行并发控制。
  • map 不能直接清空,只能 m = make(map[KeyType]ValueType)
  • map 的 key 只能是可比较类型,不能是 slice、map 或 function。

http://www.kler.cn/a/591578.html

相关文章:

  • 凸优化算法学习笔记:闵可夫斯基和与Slope trick
  • 在k8s中利用Helm部署Prometheus+Grafana和Loki日志系统
  • 什么是时序数据库?
  • mybatis_plus的乐观锁
  • 有了大语言模型还需要 RAG 做什么
  • windows下使用vscode+cline插件体验MCP,体验使用AI控制浏览器,踩坑记录(至少让你节省3个小时弯路版)(喂饭级别)
  • 【第九节】windows sdk编程:通用控件的使用
  • Pygame实现记忆拼图游戏8
  • PHP转GO Go语言环境搭建(Day1) 常见问题及解决方案指南
  • Ubuntu24.04安装ROS2 Jazzy
  • ubuntu下TFTP服务器搭建
  • 宝塔docker切换存储目录
  • 【Pytorch实战教程】拆解PyTorch中的多头注意力:原来Transformer的核心组件可以这样玩
  • leetcode每日一题:对角线上的质数
  • Qt Graphics View
  • Qt 实操记录:打造自己的“ QQ 音乐播放器”
  • 马蜂窝携手腾讯云接入DeepSeek,率先应用于旅游AI智能应用“AI游贵州”
  • Ubuntu “文件系统根目录”上的磁盘空间不足
  • 【操作系统安全】任务4:Windows 系统网络安全实践里常用 DOS 命令
  • 河南大学移动应用开发实验报告1