04.Map

在 Go 语言中,map 是一种内置的数据结构,用于存储键值对。map 提供了高效的键值对查询、插入和删除操作。下面是详细介绍 map 的使用方法及注意事项。

1. 创建和初始化 map

使用 make 函数创建

可以使用 make 函数创建一个指定类型的 map

package main

import "fmt"

func main() {
    // 创建一个 key 为 string, value 为 int 的 map
    myMap := make(map[string]int)
    fmt.Println(myMap) // 输出:map[]
}

 

使用字面量初始化

可以直接使用字面量初始化一个 map,同时设置初始值。

package main

import "fmt"

func main() {
    myMap := map[string]int{
        "one": 1,
        "two": 2,
        "three": 3,
    }
    fmt.Println(myMap) // 输出:map[one:1 two:2 three:3]
}

 

在 Go 语言中,map 是无序的。每次遍历或打印 map 中的键值对时,它们的顺序可能不同。这个特性是由 Go 语言的内部实现决定的。即使你使用相同的代码,多次运行也可能得到不同的键值对顺序。

具体原因如下:

  1. 内部哈希实现map 的键是通过哈希算法计算得到的,而哈希算法的结果在内存布局中并不保证顺序。

  2. 优化性能:Go 语言的 map 实现为了优化性能和内存使用,没有对键值对进行排序。因此,每次遍历或打印时的顺序可能不同。

2. 操作 map

添加和更新元素

使用 map[key] = value 的语法添加或更新 map 中的元素。

package main

import "fmt"

func main() {
    myMap := make(map[string]int)
    myMap["one"] = 1
    myMap["two"] = 2
    fmt.Println(myMap) // 输出:map[one:1 two:2]

    // 更新元素
    myMap["one"] = 10
    fmt.Println(myMap) // 输出:map[one:10 two:2]
}

 

访问元素

使用 map[key] 的语法访问 map 中的元素。可以使用两个返回值的方式来判断键是否存在。

package main

import "fmt"

func main() {
    myMap := map[string]int{"one": 1, "two": 2}
    
    value := myMap["one"]
    fmt.Println("Value for 'one':", value) // 输出:Value for 'one': 1
    
    // 判断键是否存在
    value, ok := myMap["three"]
    if ok {
        fmt.Println("Value for 'three':", value)
    } else {
        fmt.Println("'three' does not exist") // 输出: 'three' does not exist
    }
}

 

删除元素

使用 delete 函数从 map 中删除元素。

package main

import "fmt"

func main() {
    myMap := map[string]int{"one": 1, "two": 2}
    
    delete(myMap, "one")
    fmt.Println(myMap) // 输出:map[two:2]
}

 

3. 遍历 map

使用 for range 语法遍历 map 中的所有键值对。

package main

import "fmt"

func main() {
    myMap := map[string]int{"one": 1, "two": 2, "three": 3}
    
    for key, value := range myMap {
        fmt.Printf("Key: %s, Value: %d\n", key, value)
    }
}

 

4. 注意事项

map 是无序的

map 中的键值对是无序的,每次遍历的顺序可能不同。

零值

map 的零值是 nil,一个 nilmap 不能用于存储键值对,否则会引发运行时错误。

package main

import "fmt"

func main() {
    var myMap map[string]int
    fmt.Println(myMap == nil) // 输出:true
    
    // 下面的操作会引发运行时错误:panic: assignment to entry in nil map
    // myMap["one"] = 1
}

 

并发访问

map 不是并发安全的。如果需要在多个 goroutine 中并发读写同一个 map,需要使用同步机制(如 sync.Mutexsync.RWMutex)来确保安全。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    myMap := make(map[string]int)
    var mu sync.Mutex

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            mu.Lock()
            myMap[fmt.Sprintf("key%d", i)] = i
            mu.Unlock()
        }(i)
    }

    wg.Wait()
    fmt.Println(myMap)
}

 

示例代码

下面是一个综合使用 map 的示例代码:

package main

import "fmt"

func main() {
    // 创建并初始化 map
    myMap := map[string]int{"one": 1, "two": 2, "three": 3}

    // 添加和更新元素
    myMap["four"] = 4
    myMap["one"] = 10

    // 访问元素
    value, ok := myMap["two"]
    if ok {
        fmt.Println("Value for 'two':", value)
    }

    // 删除元素
    delete(myMap, "three")

    // 遍历 map
    for key, value := range myMap {
        fmt.Printf("Key: %s, Value: %d\n", key, value)
    }
}

 

posted @ 2024-07-09 00:54  JJJhr  阅读(6)  评论(0编辑  收藏  举报