V
Vel·ToolKit
简洁 · 高效 · 即开即用
ZH
第 7 章 / 共 20 章

映射 map

声明、增删查、遍历、并发安全

声明与初始化

package main

import "fmt"

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

    // 用 make
    m2 := make(map[string]int)
    m2["x"] = 1

    fmt.Println(m, m2)
}

读 / 写 / 删除

package main

import "fmt"

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

    m["alice"] = 31         // 写
    v := m["alice"]         // 读
    fmt.Println(v)

    if cv, ok := m["carol"]; ok { // 判断是否存在
        fmt.Println("carol:", cv)
    } else {
        fmt.Println("carol missing")
    }

    delete(m, "bob") // 删
    fmt.Println(m)
}

遍历

range 遍历 map 的顺序是随机的,需要顺序请先把 key 排序。

package main

import (
    "fmt"
    "sort"
)

func main() {
    m := map[string]int{"bob": 1, "alice": 2, "carol": 3}

    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    for _, k := range keys {
        fmt.Println(k, m[k])
    }
}

并发安全

map 不是并发安全的。多 goroutine 读写需要加锁,或使用 sync.Map(适合读多写少、key 集合相对稳定的场景)。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var (
        mu sync.Mutex
        m  = map[string]int{}
    )
    set := func(k string, v int) {
        mu.Lock()
        defer mu.Unlock()
        m[k] = v
    }

    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            set(fmt.Sprintf("k%d", i), i)
        }(i)
    }
    wg.Wait()
    fmt.Println(len(m))
}