Go语言映射(Map)类型详解

Go语言映射(Map)类型详解

编码文章call10242025-05-30 11:19:3517A+A-

一、映射(Map)基本概念

  • 定义:map 是一种 键值对(Key-Value) 的无序集合,键唯一,值可重复。
  • 特点
    • 引用类型:赋值或传参时传递引用,共享底层数据。
    • 动态增长:无需预先声明容量,自动扩容。
    • 键类型限制:键必须是可比较类型(如 int、string、struct 等),切片、函数等不可比较类型不能作为键。

二、声明与初始化

  1. 声明空Map
var m1 map[string]int      // 声明一个键为string、值为int的map(此时m1为nil)
m2 := make(map[string]int) // 使用make初始化(推荐)
  1. 直接初始化
m3 := map[string]int{       // 字面量初始化
    "apple":  5,
    "banana": 3,
}
  1. 预分配容量(优化性能):
m4 := make(map[string]float64, 100) // 初始容量100,减少扩容开销

三、基本操作

  1. 添加/修改元素
m := make(map[string]int)
m["apple"] = 10    // 添加键值对
m["banana"] = 7
m["apple"] = 15    // 修改已有键的值
  1. 删除元素
delete(m, "banana") // 删除键"banana"对应的键值对
  1. 访问元素
value := m["apple"]  // 获取值(若键不存在,返回值类型的零值)

// 检查键是否存在
value, exists := m["orange"]
if exists {
    fmt.Println("Orange exists:", value)
} else {
    fmt.Println("Orange not found")
}
  1. 遍历Map
for key, value := range m {
    fmt.Printf("%s: %d\n", key, value) // 遍历顺序不固定
}

四、高级用法

  1. 嵌套Map
// 学生成绩表:学生名 -> 科目 -> 分数
scores := map[string]map[string]int{
    "Alice": {
        "Math": 90,
        "English": 85,
    },
    "Bob": {
        "Math": 78,
    },
}

// 访问嵌套值
fmt.Println(scores["Alice"]["Math"]) // 输出:90
  1. 用Map实现集合
set := make(map[string]struct{}) // 值类型为空结构体(零内存开销)
set["a"] = struct{}{}
set["b"] = struct{}{}

// 检查元素是否存在
if _, ok := set["a"]; ok {
    fmt.Println("a exists")
}
  1. 并发安全
import "sync"

var safeMap sync.Map          // 使用sync.Map(线程安全)
safeMap.Store("key", "value") // 存储
val, ok := safeMap.Load("key") // 读取

五、注意事项

  1. 空Map与nil Map
var nilMap map[string]int    // nil,不可直接操作(panic)
emptyMap := make(map[string]int) // 空map,可安全使用
  1. 零值处理
m := map[string]int{"apple": 5}
fmt.Println(m["banana"]) // 输出0(int的零值)
  1. 键的唯一性
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。
点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4