Map 映射

Map 是 Go 语言中的键值对(key-value)数据结构,类似于其他语言的字典(Dictionary)或哈希表(HashMap)。

什么是 Map?

Map 是一种无序的键值对集合,通过键(key)可以快速找到对应的值(value)。

Map 结构示意:

┌──────────────────────────────────┐
│    Key        │      Value       │
├───────────────┼──────────────────┤
│   "name"      │     "张三"       │
│   "age"       │       25         │
│   "city"      │     "北京"       │
└───────────────┴──────────────────┘

Map 的特点

特点说明
无序元素顺序不固定
键唯一每个键只能出现一次
键类型限制键必须是可比较的类型
引用类型赋值和传参共享底层数据

创建 Map

方式一:make 函数

package main

import "fmt"

func main() {
    m := make(map[string]int)
    m["age"] = 25
    fmt.Printf("m: %v\n", m)
}

方式二:字面量

package main

import "fmt"

func main() {
    m := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }
    fmt.Printf("m: %v\n", m)
}

方式三:空 map

package main

import "fmt"

func main() {
    var m map[string]int
    fmt.Printf("m: %v, nil: %v\n", m, m == nil)

    m = make(map[string]int)
    m["key"] = 1
    fmt.Printf("m: %v\n", m)
}

注意:var m map[string]int 声明的是 nil map,不能直接赋值,需要先 make。

Map 基本操作

添加元素

package main

import "fmt"

func main() {
    m := make(map[string]string)
    m["name"] = "张三"
    m["city"] = "北京"
    fmt.Printf("m: %v\n", m)
}

获取元素

package main

import "fmt"

func main() {
    m := map[string]int{
        "age": 25,
    }

    age := m["age"]
    fmt.Printf("age: %d\n", age)

    name := m["name"]
    fmt.Printf("name: %d\n", name)
}

检查键是否存在

package main

import "fmt"

func main() {
    m := map[string]int{
        "age": 25,
    }

    value, exists := m["age"]
    if exists {
        fmt.Printf("age 存在,值: %d\n", value)
    }

    value, exists = m["name"]
    if !exists {
        fmt.Println("name 不存在")
    }
}

输出:

age 存在,值: 25
name 不存在

修改元素

package main

import "fmt"

func main() {
    m := map[string]int{
        "age": 25,
    }
    fmt.Printf("修改前: %v\n", m)

    m["age"] = 26
    fmt.Printf("修改后: %v\n", m)
}

删除元素

package main

import "fmt"

func main() {
    m := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }
    fmt.Printf("删除前: %v\n", m)

    delete(m, "two")
    fmt.Printf("删除后: %v\n", m)
}

获取长度

package main

import "fmt"

func main() {
    m := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }
    fmt.Printf("map 长度: %d\n", len(m))
}

遍历 Map

for-range 遍历

package main

import "fmt"

func main() {
    m := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }

    for key, value := range m {
        fmt.Printf("key: %s, value: %d\n", key, value)
    }
}

只遍历键或值

package main

import "fmt"

func main() {
    m := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }

    fmt.Println("只遍历键:")
    for key := range m {
        fmt.Printf("key: %s\n", key)
    }

    fmt.Println("\n只遍历值:")
    for _, value := range m {
        fmt.Printf("value: %d\n", value)
    }
}

注意:Map 遍历顺序是随机的,不能依赖遍历顺序。

Map 是引用类型

package main

import "fmt"

func modifyMap(m map[string]int) {
    m["new"] = 100
}

func main() {
    m := map[string]int{
        "one": 1,
    }
    fmt.Printf("修改前: %v\n", m)

    modifyMap(m)
    fmt.Printf("修改后: %v\n", m)
}

输出:

修改前: map[one:1]
修改后: map[new:100 one:1]

嵌套 Map

Map 中嵌套 Map

package main

import "fmt"

func main() {
    students := map[string]map[string]int{
        "张三": {
            "math": 90,
            "english": 85,
        },
        "李四": {
            "math": 88,
            "english": 92,
        },
    }

    for name, scores := range students {
        fmt.Printf("%s 的成绩:\n", name)
        for subject, score := range scores {
            fmt.Printf("  %s: %d\n", subject, score)
        }
    }
}

Map 中嵌套切片

package main

import "fmt"

func main() {
    m := map[string][]string{
        "fruits":  {"apple", "banana", "orange"},
        "animals": {"cat", "dog"},
    }

    for key, values := range m {
        fmt.Printf("%s: %v\n", key, values)
    }
}

实际案例

案例 1:单词计数

package main

import (
    "fmt"
    "strings"
)

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 go go"
    counts := wordCount(text)

    fmt.Printf("文本: %s\n", text)
    fmt.Println("单词计数:")
    for word, count := range counts {
        fmt.Printf("  %s: %d\n", word, count)
    }
}

输出:

文本: hello world hello go world go go
单词计数:
  hello: 2
  world: 2
  go: 3

案例 2:学生成绩管理

package main

import "fmt"

type Student struct {
    Name   string
    Scores map[string]int
}

func (s *Student) AddScore(subject string, score int) {
    s.Scores[subject] = score
}

func (s *Student) GetAverage() float64 {
    total := 0
    for _, score := range s.Scores {
        total += score
    }
    return float64(total) / float64(len(s.Scores))
}

func main() {
    student := Student{
        Name:   "张三",
        Scores: make(map[string]int),
    }

    student.AddScore("数学", 90)
    student.AddScore("英语", 85)
    student.AddScore("物理", 88)

    fmt.Printf("学生: %s\n", student.Name)
    fmt.Println("成绩:")
    for subject, score := range student.Scores {
        fmt.Printf("  %s: %d\n", subject, score)
    }
    fmt.Printf("平均分: %.2f\n", student.GetAverage())
}

案例 3:缓存实现

package main

import "fmt"

type Cache struct {
    data map[string]string
}

func NewCache() *Cache {
    return &Cache{
        data: make(map[string]string),
    }
}

func (c *Cache) Set(key, value string) {
    c.data[key] = value
}

func (c *Cache) Get(key string) (string, bool) {
    value, exists := c.data[key]
    return value, exists
}

func (c *Cache) Delete(key string) {
    delete(c.data, key)
}

func main() {
    cache := NewCache()

    cache.Set("name", "张三")
    cache.Set("city", "北京")

    if value, exists := cache.Get("name"); exists {
        fmt.Printf("name: %s\n", value)
    }

    cache.Delete("name")

    if _, exists := cache.Get("name"); !exists {
        fmt.Println("name 已被删除")
    }
}

总结

本章学习了 Go 语言的 Map:

知识点说明
创建make(map[K]V) 或字面量
添加/修改m[key] = value
获取m[key]value, ok := m[key]
删除delete(m, key)
长度len(m)
遍历for k, v := range m
类型引用类型