1.4.2 Map 映射 #
Map(映射)是 Go 语言中用于存储键值对的内置数据类型,类似于其他语言中的哈希表、字典或关联数组。Map 提供了快速的键值查找功能,是处理关联数据的重要工具。理解 Map 的特性、使用方法和最佳实践,对于编写高效的 Go 程序至关重要。
Map 的基本概念 #
Map 的特性 #
Map 是一种引用类型,具有以下重要特性:
- 无序性:Map 中的键值对没有固定的顺序
- 唯一键:每个键在 Map 中只能出现一次
- 引用类型:Map 变量存储的是指向底层数据结构的指针
- 零值:Map 的零值是
nil
,不能直接使用,需要初始化
Map 的声明和初始化 #
package main
import "fmt"
func main() {
// 1. 声明 Map 的几种方式
// 方式一:声明后使用 make 初始化
var userAges map[string]int
userAges = make(map[string]int)
userAges["张三"] = 25
userAges["李四"] = 30
fmt.Printf("用户年龄: %v\n", userAges)
// 方式二:声明时直接使用 make
scores := make(map[string]int)
scores["数学"] = 95
scores["英语"] = 87
scores["物理"] = 92
fmt.Printf("科目成绩: %v\n", scores)
// 方式三:使用 Map 字面量
colors := map[string]string{
"red": "红色",
"green": "绿色",
"blue": "蓝色",
}
fmt.Printf("颜色映射: %v\n", colors)
// 方式四:空 Map 字面量
emptyMap := map[string]int{}
emptyMap["key1"] = 100
fmt.Printf("空 Map: %v\n", emptyMap)
// 方式五:复杂类型的 Map
studentInfo := map[string]map[string]interface{}{
"student1": {
"name": "张三",
"age": 20,
"grade": "大二",
},
"student2": {
"name": "李四",
"age": 21,
"grade": "大三",
},
}
fmt.Printf("学生信息: %v\n", studentInfo)
}
Map 的基本操作 #
package main
import "fmt"
func main() {
// 创建一个存储商品价格的 Map
prices := map[string]float64{
"苹果": 5.5,
"香蕉": 3.2,
"橙子": 4.8,
"葡萄": 12.0,
}
// 1. 访问 Map 元素
fmt.Printf("苹果的价格: %.2f 元\n", prices["苹果"])
// 2. 检查键是否存在
price, exists := prices["西瓜"]
if exists {
fmt.Printf("西瓜的价格: %.2f 元\n", price)
} else {
fmt.Println("西瓜不在价格表中")
}
// 3. 添加新的键值对
prices["西瓜"] = 6.8
prices["芒果"] = 15.5
fmt.Printf("添加新商品后: %v\n", prices)
// 4. 修改现有值
prices["苹果"] = 6.0
fmt.Printf("修改苹果价格后: %v\n", prices)
// 5. 删除键值对
delete(prices, "香蕉")
fmt.Printf("删除香蕉后: %v\n", prices)
// 6. 获取 Map 长度
fmt.Printf("商品种类数量: %d\n", len(prices))
// 7. 遍历 Map
fmt.Println("所有商品价格:")
for product, price := range prices {
fmt.Printf("%s: %.2f 元\n", product, price)
}
// 8. 只遍历键
fmt.Println("所有商品名称:")
for product := range prices {
fmt.Printf("- %s\n", product)
}
// 9. 只遍历值
fmt.Println("所有价格:")
for _, price := range prices {
fmt.Printf("%.2f 元 ", price)
}
fmt.Println()
}
Map 的高级用法 #
不同类型的 Map #
package main
import "fmt"
func main() {
// 1. 整数键的 Map
monthNames := map[int]string{
1: "一月",
2: "二月",
3: "三月",
4: "四月",
5: "五月",
6: "六月",
7: "七月",
8: "八月",
9: "九月",
10: "十月",
11: "十一月",
12: "十二月",
}
fmt.Printf("第6个月: %s\n", monthNames[6])
// 2. 结构体作为键
type Point struct {
X, Y int
}
distances := map[Point]float64{
{0, 0}: 0.0,
{1, 1}: 1.414,
{3, 4}: 5.0,
}
p := Point{3, 4}
fmt.Printf("点 %v 到原点的距离: %.3f\n", p, distances[p])
// 3. 切片作为值的 Map
studentCourses := map[string][]string{
"张三": {"数学", "物理", "化学"},
"李四": {"英语", "历史", "地理"},
"王五": {"数学", "英语", "计算机"},
}
fmt.Printf("张三的课程: %v\n", studentCourses["张三"])
// 4. Map 作为值的 Map
classGrades := map[string]map[string]int{
"三年级一班": {
"数学": 85,
"语文": 88,
"英语": 82,
},
"三年级二班": {
"数学": 87,
"语文": 85,
"英语": 89,
},
}
fmt.Printf("三年级一班数学成绩: %d\n", classGrades["三年级一班"]["数学"])
// 5. 函数作为值的 Map
operations := map[string]func(int, int) int{
"add": func(a, b int) int { return a + b },
"sub": func(a, b int) int { return a - b },
"mul": func(a, b int) int { return a * b },
"div": func(a, b int) int {
if b != 0 {
return a / b
}
return 0
},
}
result := operations["add"](10, 5)
fmt.Printf("10 + 5 = %d\n", result)
result = operations["mul"](7, 8)
fmt.Printf("7 × 8 = %d\n", result)
}
Map 的并发安全 #
package main
import (
"fmt"
"sync"
"time"
)
// 线程安全的 Map 封装
type SafeMap struct {
mu sync.RWMutex
data map[string]int
}
// 创建安全的 Map
func NewSafeMap() *SafeMap {
return &SafeMap{
data: make(map[string]int),
}
}
// 设置值
func (sm *SafeMap) Set(key string, value int) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.data[key] = value
}
// 获取值
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mu.RLock()
defer sm.mu.RUnlock()
value, exists := sm.data[key]
return value, exists
}
// 删除键
func (sm *SafeMap) Delete(key string) {
sm.mu.Lock()
defer sm.mu.Unlock()
delete(sm.data, key)
}
// 获取所有键值对
func (sm *SafeMap) GetAll() map[string]int {
sm.mu.RLock()
defer sm.mu.RUnlock()
result := make(map[string]int)
for k, v := range sm.data {
result[k] = v
}
return result
}
func main() {
// 使用线程安全的 Map
safeMap := NewSafeMap()
// 启动多个 goroutine 并发写入
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
safeMap.Set(key, id*10)
fmt.Printf("Goroutine %d 设置 %s = %d\n", id, key, id*10)
}(i)
}
// 启动读取 goroutine
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
time.Sleep(time.Millisecond * 10) // 稍微延迟
key := fmt.Sprintf("key%d", id)
if value, exists := safeMap.Get(key); exists {
fmt.Printf("Goroutine 读取 %s = %d\n", key, value)
}
}(i)
}
wg.Wait()
// 打印最终结果
fmt.Println("最终结果:")
allData := safeMap.GetAll()
for k, v := range allData {
fmt.Printf("%s: %d\n", k, v)
}
}
实际应用示例 #
单词统计程序 #
package main
import (
"fmt"
"sort"
"strings"
"unicode"
)
// 单词统计结构
type WordCount struct {
Word string
Count int
}
// 清理单词(移除标点符号,转为小写)
func cleanWord(word string) string {
var result strings.Builder
for _, r := range word {
if unicode.IsLetter(r) {
result.WriteRune(unicode.ToLower(r))
}
}
return result.String()
}
// 统计单词频率
func countWords(text string) map[string]int {
wordCount := make(map[string]int)
words := strings.Fields(text)
for _, word := range words {
cleanedWord := cleanWord(word)
if cleanedWord != "" {
wordCount[cleanedWord]++
}
}
return wordCount
}
// 获取最频繁的单词
func getTopWords(wordCount map[string]int, n int) []WordCount {
// 转换为切片以便排序
var words []WordCount
for word, count := range wordCount {
words = append(words, WordCount{word, count})
}
// 按频率降序排序
sort.Slice(words, func(i, j int) bool {
return words[i].Count > words[j].Count
})
// 返回前 n 个
if n > len(words) {
n = len(words)
}
return words[:n]
}
func main() {
text := `
Go is an open source programming language that makes it easy to build
simple, reliable, and efficient software. Go was designed at Google in
2007 to improve programming productivity in an era of multicore machines,
networked systems, and large codebases. Go is expressive, concise, clean,
and efficient. Its concurrency mechanisms make it easy to write programs
that get the most out of multicore and networked machines, while its novel
type system enables flexible and modular program construction.
`
fmt.Println("原文:")
fmt.Println(text)
// 统计单词频率
wordCount := countWords(text)
fmt.Printf("\n总共有 %d 个不同的单词\n", len(wordCount))
// 显示所有单词及其频率
fmt.Println("\n所有单词频率:")
for word, count := range wordCount {
fmt.Printf("%s: %d\n", word, count)
}
// 显示最频繁的前5个单词
fmt.Println("\n最频繁的前5个单词:")
topWords := getTopWords(wordCount, 5)
for i, wc := range topWords {
fmt.Printf("%d. %s: %d 次\n", i+1, wc.Word, wc.Count)
}
// 查找特定单词
searchWords := []string{"go", "programming", "system"}
fmt.Println("\n特定单词统计:")
for _, word := range searchWords {
if count, exists := wordCount[word]; exists {
fmt.Printf("'%s' 出现了 %d 次\n", word, count)
} else {
fmt.Printf("'%s' 没有出现\n", word)
}
}
}
学生成绩管理系统 #
package main
import (
"fmt"
"sort"
)
// 学生结构
type Student struct {
ID string
Name string
Scores map[string]float64 // 科目 -> 成绩
}
// 成绩管理系统
type GradeManager struct {
students map[string]*Student // 学号 -> 学生
subjects []string // 所有科目
}
// 创建成绩管理系统
func NewGradeManager() *GradeManager {
return &GradeManager{
students: make(map[string]*Student),
subjects: make([]string, 0),
}
}
// 添加学生
func (gm *GradeManager) AddStudent(id, name string) {
gm.students[id] = &Student{
ID: id,
Name: name,
Scores: make(map[string]float64),
}
}
// 添加科目
func (gm *GradeManager) AddSubject(subject string) {
for _, s := range gm.subjects {
if s == subject {
return // 科目已存在
}
}
gm.subjects = append(gm.subjects, subject)
}
// 录入成绩
func (gm *GradeManager) SetScore(studentID, subject string, score float64) error {
student, exists := gm.students[studentID]
if !exists {
return fmt.Errorf("学生 %s 不存在", studentID)
}
// 确保科目存在
gm.AddSubject(subject)
student.Scores[subject] = score
return nil
}
// 获取学生成绩
func (gm *GradeManager) GetStudentScores(studentID string) (*Student, error) {
student, exists := gm.students[studentID]
if !exists {
return nil, fmt.Errorf("学生 %s 不存在", studentID)
}
return student, nil
}
// 计算学生平均分
func (gm *GradeManager) GetStudentAverage(studentID string) (float64, error) {
student, err := gm.GetStudentScores(studentID)
if err != nil {
return 0, err
}
if len(student.Scores) == 0 {
return 0, nil
}
total := 0.0
for _, score := range student.Scores {
total += score
}
return total / float64(len(student.Scores)), nil
}
// 获取科目平均分
func (gm *GradeManager) GetSubjectAverage(subject string) float64 {
total := 0.0
count := 0
for _, student := range gm.students {
if score, exists := student.Scores[subject]; exists {
total += score
count++
}
}
if count == 0 {
return 0
}
return total / float64(count)
}
// 获取排名
func (gm *GradeManager) GetRanking() []struct {
Student *Student
Average float64
} {
type StudentRank struct {
Student *Student
Average float64
}
var rankings []StudentRank
for _, student := range gm.students {
avg, _ := gm.GetStudentAverage(student.ID)
rankings = append(rankings, StudentRank{student, avg})
}
// 按平均分降序排序
sort.Slice(rankings, func(i, j int) bool {
return rankings[i].Average > rankings[j].Average
})
return rankings
}
// 打印成绩单
func (gm *GradeManager) PrintReport() {
fmt.Println("=== 成绩报告 ===")
// 打印所有学生成绩
for _, student := range gm.students {
fmt.Printf("\n学生: %s (%s)\n", student.Name, student.ID)
for subject, score := range student.Scores {
fmt.Printf(" %s: %.2f\n", subject, score)
}
avg, _ := gm.GetStudentAverage(student.ID)
fmt.Printf(" 平均分: %.2f\n", avg)
}
// 打印科目统计
fmt.Println("\n=== 科目统计 ===")
for _, subject := range gm.subjects {
avg := gm.GetSubjectAverage(subject)
fmt.Printf("%s 平均分: %.2f\n", subject, avg)
}
// 打印排名
fmt.Println("\n=== 学生排名 ===")
rankings := gm.GetRanking()
for i, rank := range rankings {
fmt.Printf("%d. %s: %.2f\n", i+1, rank.Student.Name, rank.Average)
}
}
func main() {
// 创建成绩管理系统
gm := NewGradeManager()
// 添加学生
gm.AddStudent("001", "张三")
gm.AddStudent("002", "李四")
gm.AddStudent("003", "王五")
gm.AddStudent("004", "赵六")
// 录入成绩
subjects := []string{"数学", "语文", "英语", "物理", "化学"}
scores := map[string]map[string]float64{
"001": {"数学": 95, "语文": 87, "英语": 92, "物理": 88, "化学": 90},
"002": {"数学": 88, "语文": 92, "英语": 85, "物理": 91, "化学": 87},
"003": {"数学": 92, "语文": 89, "英语": 94, "物理": 86, "化学": 93},
"004": {"数学": 85, "语文": 91, "英语": 88, "物理": 89, "化学": 86},
}
for studentID, studentScores := range scores {
for subject, score := range studentScores {
gm.SetScore(studentID, subject, score)
}
}
// 打印报告
gm.PrintReport()
// 查询特定学生
fmt.Println("\n=== 查询张三的成绩 ===")
if student, err := gm.GetStudentScores("001"); err == nil {
fmt.Printf("学生: %s\n", student.Name)
for subject, score := range student.Scores {
fmt.Printf("%s: %.2f\n", subject, score)
}
if avg, err := gm.GetStudentAverage("001"); err == nil {
fmt.Printf("平均分: %.2f\n", avg)
}
}
}
缓存系统实现 #
package main
import (
"fmt"
"sync"
"time"
)
// 缓存项
type CacheItem struct {
Value interface{}
Expiration int64
}
// 检查是否过期
func (item *CacheItem) IsExpired() bool {
if item.Expiration == 0 {
return false // 永不过期
}
return time.Now().UnixNano() > item.Expiration
}
// 内存缓存
type MemoryCache struct {
mu sync.RWMutex
items map[string]*CacheItem
}
// 创建缓存
func NewMemoryCache() *MemoryCache {
cache := &MemoryCache{
items: make(map[string]*CacheItem),
}
// 启动清理过期项的 goroutine
go cache.cleanupExpired()
return cache
}
// 设置缓存项
func (mc *MemoryCache) Set(key string, value interface{}, duration time.Duration) {
mc.mu.Lock()
defer mc.mu.Unlock()
var expiration int64
if duration > 0 {
expiration = time.Now().Add(duration).UnixNano()
}
mc.items[key] = &CacheItem{
Value: value,
Expiration: expiration,
}
}
// 获取缓存项
func (mc *MemoryCache) Get(key string) (interface{}, bool) {
mc.mu.RLock()
defer mc.mu.RUnlock()
item, exists := mc.items[key]
if !exists {
return nil, false
}
if item.IsExpired() {
return nil, false
}
return item.Value, true
}
// 删除缓存项
func (mc *MemoryCache) Delete(key string) {
mc.mu.Lock()
defer mc.mu.Unlock()
delete(mc.items, key)
}
// 清空缓存
func (mc *MemoryCache) Clear() {
mc.mu.Lock()
defer mc.mu.Unlock()
mc.items = make(map[string]*CacheItem)
}
// 获取缓存大小
func (mc *MemoryCache) Size() int {
mc.mu.RLock()
defer mc.mu.RUnlock()
return len(mc.items)
}
// 获取所有键
func (mc *MemoryCache) Keys() []string {
mc.mu.RLock()
defer mc.mu.RUnlock()
keys := make([]string, 0, len(mc.items))
for key, item := range mc.items {
if !item.IsExpired() {
keys = append(keys, key)
}
}
return keys
}
// 清理过期项
func (mc *MemoryCache) cleanupExpired() {
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for {
select {
case <-ticker.C:
mc.mu.Lock()
for key, item := range mc.items {
if item.IsExpired() {
delete(mc.items, key)
}
}
mc.mu.Unlock()
}
}
}
func main() {
// 创建缓存
cache := NewMemoryCache()
// 设置一些缓存项
cache.Set("user:1", map[string]interface{}{
"name": "张三",
"age": 25,
}, time.Minute*5) // 5分钟过期
cache.Set("user:2", map[string]interface{}{
"name": "李四",
"age": 30,
}, 0) // 永不过期
cache.Set("temp_data", "这是临时数据", time.Second*3) // 3秒过期
// 获取缓存项
if value, exists := cache.Get("user:1"); exists {
fmt.Printf("用户1信息: %v\n", value)
}
if value, exists := cache.Get("user:2"); exists {
fmt.Printf("用户2信息: %v\n", value)
}
fmt.Printf("缓存大小: %d\n", cache.Size())
fmt.Printf("所有键: %v\n", cache.Keys())
// 等待临时数据过期
fmt.Println("等待3秒...")
time.Sleep(time.Second * 4)
if value, exists := cache.Get("temp_data"); exists {
fmt.Printf("临时数据: %v\n", value)
} else {
fmt.Println("临时数据已过期")
}
fmt.Printf("过期后缓存大小: %d\n", cache.Size())
fmt.Printf("过期后所有键: %v\n", cache.Keys())
// 演示并发访问
fmt.Println("\n演示并发访问:")
var wg sync.WaitGroup
// 并发写入
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("concurrent:%d", id)
cache.Set(key, fmt.Sprintf("value_%d", id), time.Minute)
fmt.Printf("设置 %s\n", key)
}(i)
}
// 并发读取
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("concurrent:%d", id)
if value, exists := cache.Get(key); exists {
fmt.Printf("读取 %s: %v\n", key, value)
}
}(i)
}
wg.Wait()
fmt.Printf("最终缓存大小: %d\n", cache.Size())
}
Map 的性能优化 #
预分配和性能测试 #
package main
import (
"fmt"
"runtime"
"time"
)
// 测试 Map 性能
func benchmarkMap(size int, prealloc bool) time.Duration {
start := time.Now()
var m map[int]int
if prealloc {
m = make(map[int]int, size)
} else {
m = make(map[int]int)
}
for i := 0; i < size; i++ {
m[i] = i * 2
}
return time.Since(start)
}
// 内存使用统计
func getMemStats() (uint64, uint64) {
var m runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&m)
return m.Alloc, m.TotalAlloc
}
func main() {
sizes := []int{1000, 10000, 100000, 1000000}
fmt.Println("Map 性能测试:")
fmt.Println("大小\t\t未预分配\t预分配\t\t提升")
fmt.Println("----\t\t--------\t------\t\t----")
for _, size := range sizes {
// 测试未预分配
runtime.GC()
time1 := benchmarkMap(size, false)
// 测试预分配
runtime.GC()
time2 := benchmarkMap(size, true)
improvement := float64(time1) / float64(time2)
fmt.Printf("%d\t\t%v\t%v\t%.2fx\n",
size, time1, time2, improvement)
}
// 内存使用测试
fmt.Println("\n内存使用测试:")
before, _ := getMemStats()
// 创建大 Map
bigMap := make(map[int]string, 100000)
for i := 0; i < 100000; i++ {
bigMap[i] = fmt.Sprintf("value_%d", i)
}
after, _ := getMemStats()
fmt.Printf("Map 占用内存: %d KB\n", (after-before)/1024)
// 清理测试
fmt.Println("\n清理测试:")
fmt.Printf("清理前 Map 大小: %d\n", len(bigMap))
// 删除一半元素
for i := 0; i < 50000; i++ {
delete(bigMap, i)
}
fmt.Printf("删除一半后 Map 大小: %d\n", len(bigMap))
afterDelete, _ := getMemStats()
fmt.Printf("删除后内存: %d KB\n", (afterDelete-before)/1024)
// 强制垃圾回收
runtime.GC()
afterGC, _ := getMemStats()
fmt.Printf("GC后内存: %d KB\n", (afterGC-before)/1024)
}
最佳实践和注意事项 #
Map 使用的最佳实践 #
package main
import (
"fmt"
"reflect"
)
func main() {
// 1. 检查 Map 是否为 nil
var nilMap map[string]int
fmt.Printf("nil Map: %v\n", nilMap == nil)
// 不能向 nil Map 写入
// nilMap["key"] = 1 // 这会导致 panic
// 正确的做法
if nilMap == nil {
nilMap = make(map[string]int)
}
nilMap["key"] = 1
fmt.Printf("初始化后的 Map: %v\n", nilMap)
// 2. 安全地检查键是否存在
scores := map[string]int{
"Alice": 95,
"Bob": 87,
}
// 不好的做法:直接访问可能不存在的键
fmt.Printf("Charlie 的分数: %d\n", scores["Charlie"]) // 返回零值 0
// 好的做法:使用 comma ok 语法
if score, exists := scores["Charlie"]; exists {
fmt.Printf("Charlie 的分数: %d\n", score)
} else {
fmt.Println("Charlie 没有分数记录")
}
// 3. 正确地复制 Map
original := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
// 浅复制(只复制引用)
shallow := original
shallow["a"] = 100
fmt.Printf("修改浅复制后原始 Map: %v\n", original) // 原始 Map 也被修改
// 深复制(复制内容)
deep := make(map[string]int)
for k, v := range original {
deep[k] = v
}
deep["b"] = 200
fmt.Printf("修改深复制后原始 Map: %v\n", original) // 原始 Map 不受影响
fmt.Printf("深复制的 Map: %v\n", deep)
// 4. Map 的零值处理
var zeroMap map[string]int
fmt.Printf("零值 Map 长度: %d\n", len(zeroMap))
// 可以安全地读取零值 Map
value, exists := zeroMap["key"]
fmt.Printf("从零值 Map 读取: value=%d, exists=%t\n", value, exists)
// 可以安全地遍历零值 Map
for k, v := range zeroMap {
fmt.Printf("不会执行: %s=%d\n", k, v)
}
// 5. 使用 Map 实现 Set
set := make(map[string]bool)
items := []string{"apple", "banana", "apple", "orange", "banana"}
// 添加到 Set
for _, item := range items {
set[item] = true
}
fmt.Println("Set 中的唯一元素:")
for item := range set {
fmt.Printf("- %s\n", item)
}
// 检查元素是否在 Set 中
if set["apple"] {
fmt.Println("apple 在 Set 中")
}
// 6. Map 比较
map1 := map[string]int{"a": 1, "b": 2}
map2 := map[string]int{"a": 1, "b": 2}
map3 := map[string]int{"a": 1, "b": 3}
// Map 不能直接比较,需要使用 reflect.DeepEqual
fmt.Printf("map1 == map2: %t\n", reflect.DeepEqual(map1, map2))
fmt.Printf("map1 == map3: %t\n", reflect.DeepEqual(map1, map3))
// 或者手动比较
fmt.Printf("手动比较 map1 和 map2: %t\n", mapsEqual(map1, map2))
fmt.Printf("手动比较 map1 和 map3: %t\n", mapsEqual(map1, map3))
}
// 手动比较两个 Map 是否相等
func mapsEqual(a, b map[string]int) bool {
if len(a) != len(b) {
return false
}
for k, v := range a {
if bv, exists := b[k]; !exists || bv != v {
return false
}
}
return true
}
小结 #
本节详细介绍了 Go 语言中的 Map 数据类型,主要内容包括:
Map 的特性 #
- 键值对存储:提供快速的键值查找功能
- 引用类型:Map 变量存储指向底层数据结构的指针
- 无序性:Map 中的元素没有固定顺序
- 唯一键:每个键只能出现一次
基本操作 #
- 创建:使用
make()
函数或字面量语法 - 访问:使用
map[key]
语法,支持 comma ok 模式 - 修改:直接赋值或使用
delete()
函数删除 - 遍历:使用
range
关键字
高级用法 #
- 不同类型的键值:支持多种可比较类型作为键
- 嵌套 Map:Map 的值可以是其他复合类型
- 并发安全:需要使用互斥锁保证线程安全
- 性能优化:预分配容量可以提高性能
实际应用 #
- 数据统计:单词频率统计、数据分析
- 缓存系统:内存缓存的实现
- 配置管理:键值对配置存储
- 索引构建:快速查找和检索
最佳实践 #
- 检查 Map 是否为 nil 再使用
- 使用 comma ok 语法安全地访问键
- 理解浅复制和深复制的区别
- 在并发环境中使用适当的同步机制
- 预分配 Map 容量以提高性能
Map 是 Go 语言中非常重要和常用的数据类型,掌握其使用方法和最佳实践对于编写高效的 Go 程序至关重要。
练习题:
- 实现一个 LRU(最近最少使用)缓存
- 编写程序统计文本中每个字符的出现频率
- 实现一个简单的路由器,支持路径参数匹配
- 创建一个线程安全的计数器,支持增减操作
- 实现一个简单的内存数据库,支持基本的 CRUD 操作