映射(Map)
Map是键值对的无序集合。
创建Map
使用make创建
go
// 创建空map
ages := make(map[string]int)
// 添加元素
ages["张三"] = 25
ages["李四"] = 30使用字面量创建
go
scores := map[string]int{
"数学": 95,
"语文": 87,
"英语": 92,
}创建空map
go
// 空map,可以直接使用
m1 := make(map[string]int)
// nil map,需要初始化后才能使用
var m2 map[string]int
m2 = make(map[string]int) // 必须初始化Map操作
访问元素
go
scores := map[string]int{
"数学": 95,
"语文": 87,
}
// 访问元素
mathScore := scores["数学"]
fmt.Println("数学分数:", mathScore) // 95
// 访问不存在的键,返回零值
physicsScore := scores["物理"]
fmt.Println("物理分数:", physicsScore) // 0检查键是否存在
go
scores := map[string]int{"数学": 95}
// 使用双返回值检查
if score, exists := scores["物理"]; exists {
fmt.Println("物理分数:", score)
} else {
fmt.Println("没有找到物理分数")
}修改元素
go
scores := map[string]int{"数学": 95}
// 修改
scores["数学"] = 100
// 添加
scores["物理"] = 88删除元素
go
scores := map[string]int{
"数学": 95,
"语文": 87,
}
delete(scores, "语文") // 删除键"语文"获取长度
go
scores := map[string]int{"数学": 95, "语文": 87}
fmt.Println(len(scores)) // 2遍历Map
go
scores := map[string]int{
"数学": 95,
"语文": 87,
"英语": 92,
}
// 遍历键值对
for subject, score := range scores {
fmt.Printf("%s: %d\n", subject, score)
}
// 只遍历键
for subject := range scores {
fmt.Println("科目:", subject)
}注意
Map的遍历顺序是随机的,每次遍历结果可能不同。
Map示例
完整示例
go
package main
import "fmt"
func main() {
// 创建学生成绩map
scores := make(map[string]map[string]int)
// 添加学生成绩
scores["张三"] = map[string]int{
"数学": 95,
"语文": 87,
"英语": 92,
}
scores["李四"] = map[string]int{
"数学": 88,
"语文": 90,
"英语": 85,
}
// 遍历所有学生成绩
for name, subjects := range scores {
fmt.Printf("\n%s的成绩:\n", name)
total := 0
for subject, score := range subjects {
fmt.Printf(" %s: %d\n", subject, score)
total += score
}
fmt.Printf(" 平均分: %.1f\n", float64(total)/float64(len(subjects)))
}
}统计单词出现次数
go
func wordCount(text string) map[string]int {
words := strings.Fields(text)
counts := make(map[string]int)
for _, word := range words {
counts[word]++
}
return counts
}
func main() {
text := "hello world hello go world world"
counts := wordCount(text)
for word, count := range counts {
fmt.Printf("%s: %d\n", word, count)
}
// 输出:
// hello: 2
// world: 3
// go: 1
}分组
go
func groupBy(items []string, keyFunc func(string) string) map[string][]string {
groups := make(map[string][]string)
for _, item := range items {
key := keyFunc(item)
groups[key] = append(groups[key], item)
}
return groups
}
func main() {
words := []string{"apple", "banana", "avocado", "blueberry", "cherry"}
// 按首字母分组
groups := groupBy(words, func(s string) string {
return string(s[0])
})
for letter, items := range groups {
fmt.Printf("%s: %v\n", letter, items)
}
// 输出:
// a: [apple avocado]
// b: [banana blueberry]
// c: [cherry]
}Map的键类型
Map的键必须是可比较的类型:
支持的类型
- 基本类型:int、float、string、bool
- 指针
- 数组
- 结构体(字段都可比较)
- 接口类型
不支持的类型
- 切片
- Map
- 函数
go
// 正确
m1 := make(map[int]string)
m2 := make(map[string]int)
m3 := make(map[[3]int]string)
// 错误
// m4 := make(map[[]int]string) // 切片不能作为键并发安全
Map不是并发安全的,在并发环境下需要加锁:
go
import "sync"
type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mu.RLock()
defer sm.mu.RUnlock()
val, ok := sm.m[key]
return val, ok
}
func (sm *SafeMap) Set(key string, value int) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.m[key] = value
}或者使用 sync.Map:
go
var m sync.Map
// 存储
m.Store("key", "value")
// 读取
if val, ok := m.Load("key"); ok {
fmt.Println(val)
}
// 删除
m.Delete("key")
// 遍历
m.Range(func(key, value interface{}) bool {
fmt.Printf("%v: %v\n", key, value)
return true
})