1933 字
约 6 分钟
12
8. Go语言Map
2026-09-25
无标签
  1. Go语言Map 秀才 2025年2月14日 大约 7 分钟 Go语言 Go语言 golang go基础语法 map 哈希表 此页内容 1. Map的本质:"键值对储物间" 1.1 什么是Map? 1.2 Map的定义方式 1.3 Map的基本操作 1.4 判断键是否存在 2. Map的进阶用法 2.1 嵌套Map 2.2 Map作为函数参数 3. 使用技巧和注意事项 3.1 Map的随机遍历 3.2 Map的并发���全问题 4. 实际应用场景 5. 小结 Map是Go语言中的一个重要的数据结构,它提供了键值对的存储方式,类似其他语言中的哈希表或字典。 1. Map的本质:"键值对储物间" 1.1 什么是Map? 可以把Map想象成一个特殊的储物间,每个物品(值)都有自己的标签(键)。通过这个标签,我们可以快速找到对应的物品。比如:一个存储学生成绩的系统,学号就是键,分数就是值。 1.2 Map的定义方式 在Go语言中,定义Map有几种常用方式:
// 1. 使用make函数创建
scoreMap := make(map[string]int)

// 2. 创建时直接初始化
studentScores := map[string]int{
 "张三": 95,
 "李四": 88,
 "王五": 92,
}

// 3. 声明一个空map
var prices map[string]float64
// 注意:声明后需要通过make初始化才能使用
prices = make(map[string]float64)

1.3 Map的基本操作

package main

import "fmt"

func main() {
 // 创建一个存储水果价格的map
 fruitPrices := make(map[string]float64)
 
 // 添加键值对
 fruitPrices["苹果"] = 5.5
 fruitPrices["香蕉"] = 3.8
 fruitPrices["橙子"] = 4.2
 
 // 获取值
 applePrice := fruitPrices["苹果"]
 fmt.Printf("苹果的价格是:%.2f元\n", applePrice)
 
 // 修改值
 fruitPrices["苹果"] = 5.8
 
 // 删除键值对
 delete(fruitPrices, "香蕉")
 
 // 遍历map
 for fruit, price := range fruitPrices {
 fmt.Printf("%s的价格是:%.2f元\n", fruit, price)
 }
}

运行结果:

苹果的价格是:5.50元
苹果的价格是:5.80元
橙子的价格是:4.20元

1.4 判断键是否存在 在Go语言中,访问map中不存在的键会返回该类型的零值。因此,我们需要一种方法来判断键是否真实存在:

package main

import "fmt"

func main() {
 userAge := map[string]int{
 "Alice": 25,
 "Bob": 30,
 }
 
 // 使用两个变量接收返回值
 age, exists := userAge["Tom"]
 if exists {
 fmt.Printf("Tom的年龄是:%d\n", age)
 } else {
 fmt.Println("Tom不在map中")
 }
}

运行结果:

Tom不在map中
  1. Map的进阶用法 2.1 嵌套Map Map的值可以是另一个Map,这样就形成了嵌套结构:
package main

import "fmt"

func main() {
 // 创建一个存储学生成绩的嵌套map
 studentScores := map[string]map[string]int{
 "张三": {
 "数学": 95,
 "英语": 88,
 "语文": 92,
 },
 "李四": {
 "数学": 90,
 "英语": 85,
 "语文": 88,
 },
 }
 
 // 获取张三的英语成绩
 englishScore := studentScores["张三"]["英语"]
 fmt.Printf("张三的英语成绩是:%d\n", englishScore)
}

运行结果:

张三的英语成绩是:88

2.2 Map作为函数参数 Map是引用类型,作为函数参数时传递的是底层指针的拷贝:

func updatePrice(prices map[string]float64, fruit string, price float64) {
 prices[fruit] = price
}

func main() {
 fruitPrices := map[string]float64{
 "苹果": 5.5,
 "香蕉": 3.8,
 }
 
 updatePrice(fruitPrices, "苹果", 6.0)
 fmt.Printf("更新后苹果的价格:%.2f\n", fruitPrices["苹果"])
}
  1. 使用技巧和注意事项 初始化容量
// 如果知道map大约需要存储多少键值对,可以在创建时指定容量
userAges := make(map[string]int, 100)

并发安全

// map不是并发安全的,需要使用sync.Map或互斥锁来保证并发安全
import "sync"
var mutex sync.Mutex
mutex.Lock()
map操作
mutex.Unlock()

常见陷阱 map的零值是nil,需要先初始化才能使用 不能对map的元素取地址 map的遍历顺序是随机的,不要依赖遍历顺序 3.1 Map的随机遍历

package main

import "fmt"

func main() {
 // 创建一个简单的map
 m := map[string]int{
 "a": 1,
 "b": 2,
 "c": 3,
 "d": 4,
 }
 
 // 连续遍历三次,观察输出顺序
 for i := 0; i < 3; i++ {
 fmt.Printf("第%d次遍历:\n", i+1)
 for k, v := range m {
 fmt.Printf("key: %s, value: %d\n", k, v)
 }
 fmt.Println()
 }
}

运行结果:

第1次遍历:
key: a, value: 1
key: d, value: 4
key: b, value: 2
key: c, value: 3

第2次遍历:
key: c, value: 3
key: a, value: 1
key: d, value: 4
key: b, value: 2

第3次遍历:
key: b, value: 2
key: c, value: 3
key: d, value: 4
key: a, value: 1

从输出可以看到,每次遍历的顺序都是不同的,这就是map遍历的随机性。 3.2 Map的并发安全问题 这个部分涉及到并发编程,将在后续章节中详细介绍,这里只做简单介绍,如果不是很理解的话,可以等后面学习了并发编程之后再回来看。

package main

import (
 "fmt"
 "sync"
 "time"
)

func main() {
 // 不安全的map操作
 unsafeMap := make(map[int]int)
 
 // 使用WaitGroup等待所有goroutine完成
 var wg sync.WaitGroup
 
 // 启动10个goroutine同时写map
 for i := 0; i < 10; i++ {
 wg.Add(1)
 go func(n int) {
 defer wg.Done()
 unsafeMap[n] = n // 可能导致panic
 time.Sleep(time.Millisecond)
 }(i)
 }
 
 // 安全的map操作
 var mutex sync.Mutex
 safeMap := make(map[int]int)
 
 // 再次启动10个goroutine,这次使用互斥锁保护
 for i := 0; i < 10; i++ {
 wg.Add(1)
 go func(n int) {
 defer wg.Done()
 mutex.Lock()
 safeMap[n] = n // 安全的写入
 mutex.Unlock()
 time.Sleep(time.Millisecond)
 }(i)
 }
 
 wg.Wait()
 fmt.Printf("安全的map最终内容: %v\n", safeMap)
}

运行结果:

fatal error: concurrent map writes // 第一个map可能会panic
安全的map最终内容: map[0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 8:8 9:9] // 第二个map安全执行

或者使用sync.Map:

package main

import (
 "fmt"
 "sync"
)

func main() {
 var sm sync.Map
 var wg sync.WaitGroup
 
 // 启动10个goroutine同时操作sync.Map
 for i := 0; i < 10; i++ {
 wg.Add(1)
 go func(n int) {
 defer wg.Done()
 sm.Store(n, n) // 存储键值对
 }(i)
 }
 
 wg.Wait()
 
 // 遍历sync.Map
 sm.Range(func(key, value interface{}) bool {
 fmt.Printf("key: %v, value: %v\n", key, value)
 return true
 })
}

运行结果:

key: 5, value: 5
key: 0, value: 0
key: 1, value: 1
key: 2, value: 2
key: 3, value: 3
key: 4, value: 4
key: 6, value: 6
key: 7, value: 7
key: 8, value: 8
key: 9, value: 9
  1. 实际应用场景 缓存系统
cache := make(map[string]interface{})

计数器

wordCount := make(map[string]int)
for _, word := range words {
 wordCount[word]++
}

去重

seen := make(map[string]bool)
for _, item := range items {
 seen[item] = true
}
  1. 小结 Map是Go语言中一个强大而灵活的数据结构,它提供了高效的键值对存储方案。在实际开发中,Map的应用非常广泛,从简单的数据存储到复杂的缓存系统都能见到它的身影。掌握Map的使用,对于Go程序开发来说是必不可少的。 记住:合理使用Map可以让我们的代码更加简洁高效,但也要注意并发安全等问题。选择合适的数据结构和使用方式,才能写出更好的程序。 关注秀才公众号: IT杨秀才 ,领取精品学习资料 公众号后台回复: Go面试 ,领取Go面试题库PDF 公众号后台回复: Go学习 ,领取Go必看书籍 公众号后台回复: 大模型 ,领取大模型学习资料 公众号后台回复: 111 ,领取架构学习资料 公众号后台回复: 26届秋招 ,领取26届秋招企业汇总表

    🔥 配套实战项目,拆得开、跑得起、能写进简历 多 Agent 编排 + RAG 混合检索 · 31 篇深度教程 + 50+ 面试题 点击查看 DevSupport AI 实战项目 → 在 GitHub 上编辑此页 上次编辑于: 2026/6/24 23:41:22 贡献者: Percygu , Your Name , gupeng 上一页 7. Go语言数组与切片 下一页 9. Go语言条件语句
8. Go语言Map
https://clxhxhhr.top/posts/3619/
作者
clxstart
发布于
2026-09-25
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。