一、映射(Map)基本概念
- 定义:map 是一种 键值对(Key-Value) 的无序集合,键唯一,值可重复。
- 特点:
- 引用类型:赋值或传参时传递引用,共享底层数据。
- 动态增长:无需预先声明容量,自动扩容。
- 键类型限制:键必须是可比较类型(如 int、string、struct 等),切片、函数等不可比较类型不能作为键。
二、声明与初始化
- 声明空Map:
var m1 map[string]int // 声明一个键为string、值为int的map(此时m1为nil)
m2 := make(map[string]int) // 使用make初始化(推荐)
- 直接初始化:
m3 := map[string]int{ // 字面量初始化
"apple": 5,
"banana": 3,
}
- 预分配容量(优化性能):
m4 := make(map[string]float64, 100) // 初始容量100,减少扩容开销
三、基本操作
- 添加/修改元素:
m := make(map[string]int)
m["apple"] = 10 // 添加键值对
m["banana"] = 7
m["apple"] = 15 // 修改已有键的值
- 删除元素:
delete(m, "banana") // 删除键"banana"对应的键值对
- 访问元素:
value := m["apple"] // 获取值(若键不存在,返回值类型的零值)
// 检查键是否存在
value, exists := m["orange"]
if exists {
fmt.Println("Orange exists:", value)
} else {
fmt.Println("Orange not found")
}
- 遍历Map:
for key, value := range m {
fmt.Printf("%s: %d\n", key, value) // 遍历顺序不固定
}
四、高级用法
- 嵌套Map:
// 学生成绩表:学生名 -> 科目 -> 分数
scores := map[string]map[string]int{
"Alice": {
"Math": 90,
"English": 85,
},
"Bob": {
"Math": 78,
},
}
// 访问嵌套值
fmt.Println(scores["Alice"]["Math"]) // 输出:90
- 用Map实现集合:
set := make(map[string]struct{}) // 值类型为空结构体(零内存开销)
set["a"] = struct{}{}
set["b"] = struct{}{}
// 检查元素是否存在
if _, ok := set["a"]; ok {
fmt.Println("a exists")
}
- 并发安全:
import "sync"
var safeMap sync.Map // 使用sync.Map(线程安全)
safeMap.Store("key", "value") // 存储
val, ok := safeMap.Load("key") // 读取
五、注意事项
- 空Map与nil Map:
var nilMap map[string]int // nil,不可直接操作(panic)
emptyMap := make(map[string]int) // 空map,可安全使用
- 零值处理:
m := map[string]int{"apple": 5}
fmt.Println(m["banana"]) // 输出0(int的零值)
- 键的唯一性:
m := map[string]int{"a": 1, "a": 2} // 编译错误:重复键
六、完整示例
package main
import (
"fmt"
"sync"
)
func main() {
// 初始化与操作
m := map[string]int{
"apple": 5,
"banana": 3,
}
m["orange"] = 8 // 添加
delete(m, "banana") // 删除
// 遍历
fmt.Println("遍历结果:")
for fruit, count := range m {
fmt.Printf("%s: %d\n", fruit, count)
}
// 检查键是否存在
if count, ok := m["apple"]; ok {
fmt.Printf("苹果数量:%d\n", count) // 输出:苹果数量:5
}
// 使用sync.Map
var safeMap sync.Map
safeMap.Store("name", "Alice")
val, _ := safeMap.Load("name")
fmt.Println("Name:", val) // 输出:Name: Alice
// 实现集合
set := make(map[string]struct{})
set["a"] = struct{}{}
set["b"] = struct{}{}
fmt.Println("集合包含a吗?", existsInSet(set, "a")) // 输出:true
}
// 检查集合中是否存在元素
func existsInSet(set map[string]struct{}, key string) bool {
_, ok := set[key]
return ok
}
七、总结
- 适用场景:快速查找、去重、配置管理、缓存等。
- 性能优化:预分配容量减少扩容开销,高频读写时考虑并发安全。
- 设计选择:优先使用内置 map,需要线程安全时使用 sync.Map。