Golang map 关键字
最后修改于 2025 年 5 月 7 日
本教程解释了如何在 Go 中使用 map 关键字。我们将通过创建和操作 map 的实际示例来介绍 map 的基础知识。
map 是一个内置的数据类型,它将键与值关联起来。它是 Go 对其他语言中哈希表或字典的实现。
在 Go 中,map 是无序集合,其中每个键都必须是唯一的。它们提供了高效的查找、插入和删除操作。
基本 map 声明和初始化
此示例展示了如何声明和初始化一个具有字符串键和整数值的 map。它演示了基本的 map 操作。
package main
import "fmt"
func main() {
// Declare and initialize a map
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Carol": 28,
}
// Access a value
fmt.Println("Alice's age:", ages["Alice"])
// Add a new key-value pair
ages["Dave"] = 32
// Update a value
ages["Bob"] = 31
// Delete a key
delete(ages, "Carol")
fmt.Println("Updated map:", ages)
}
map 使用三个键值对进行初始化。我们演示了访问、添加、更新和删除元素。Map 是动态的,可以根据需要增长。
检查键是否存在
此示例展示了如何检查 map 中是否存在某个键。Go 为此提供了特殊的语法。
package main
import "fmt"
func main() {
colors := map[string]string{
"red": "#FF0000",
"green": "#00FF00",
"blue": "#0000FF",
}
// Check if key exists
value, exists := colors["red"]
if exists {
fmt.Println("Red's hex code:", value)
} else {
fmt.Println("Red not found")
}
// Check for non-existent key
value, exists = colors["yellow"]
if exists {
fmt.Println("Yellow's hex code:", value)
} else {
fmt.Println("Yellow not found")
}
}
双值赋值用于检查键是否存在。第二个布尔值指示键是否存在。这可以防止与零值混淆。
遍历 map
可以使用 range 关键字遍历 map。此示例展示了如何循环遍历所有键值对。
package main
import "fmt"
func main() {
capitals := map[string]string{
"USA": "Washington D.C.",
"France": "Paris",
"Japan": "Tokyo",
"India": "New Delhi",
}
// Iterate over all key-value pairs
for country, capital := range capitals {
fmt.Printf("The capital of %s is %s\n", country, capital)
}
// Iterate just over keys
for country := range capitals {
fmt.Println("Country:", country)
}
}
range 关键字同时返回键和值。由于 map 是无序集合,因此不保证顺序。通过省略值可以单独访问键。
Map of slices
此示例演示了一个值是 slice 的 map。它展示了如何处理更复杂的 map 结构。
package main
import "fmt"
func main() {
// Map of string slices
classes := map[string][]string{
"math": {"algebra", "calculus", "geometry"},
"science": {"biology", "chemistry", "physics"},
}
// Add a new subject
classes["history"] = []string{"world", "european", "american"}
// Append to an existing slice
classes["math"] = append(classes["math"], "statistics")
// Print all subjects
for subject, topics := range classes {
fmt.Printf("%s: %v\n", subject, topics)
}
}
map 将 slice 作为值存储。我们演示了初始化、添加新键以及向现有 slice 追加元素。这种模式对于分组数据很常见。
Map 长度和 nil maps
此示例涵盖了 map 长度以及 nil map 和空 map 之间的区别。理解这一点对于正确使用 map 至关重要。
package main
import "fmt"
func main() {
// Nil map (cannot be used directly)
var nilMap map[string]int
fmt.Println("Nil map:", nilMap)
// Empty initialized map
emptyMap := make(map[string]int)
fmt.Println("Empty map:", emptyMap)
// Check length
populatedMap := map[string]int{"a": 1, "b": 2}
fmt.Println("Map length:", len(populatedMap))
// Initialize nil map before use
nilMap = make(map[string]int)
nilMap["now"] = 1
fmt.Println("Initialized nil map:", nilMap)
}
Nil maps 在初始化之前无法存储值。len 函数返回键值对的数量。始终在初始化后使用 map。
Map 作为函数参数
Map 是 Go 中的引用类型。此示例显示了将 map 传递给函数时它们的行为。
package main
import "fmt"
func updateMap(m map[string]int, key string, value int) {
m[key] = value
}
func main() {
scores := map[string]int{
"Alice": 90,
"Bob": 85,
}
fmt.Println("Before update:", scores)
updateMap(scores, "Alice", 95)
updateMap(scores, "Carol", 88)
fmt.Println("After update:", scores)
}
Map 是通过引用传递的,因此函数内部的修改会影响原始 map。无需指针即可修改 map 内容。
并发 map 访问
此示例演示了在从多个 goroutine 访问 map 时进行同步的必要性。
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var mu sync.Mutex
sharedMap := make(map[int]int)
// Write to map from multiple goroutines
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
mu.Lock()
sharedMap[n] = n * n
mu.Unlock()
}(i)
}
wg.Wait()
// Read from map
mu.Lock()
for k, v := range sharedMap {
fmt.Printf("%d: %d\n", k, v)
}
mu.Unlock()
}
Map 不是线程安全的。并发访问需要使用互斥锁进行同步。此示例使用 sync.Mutex 来保护 map 操作。
来源
本教程通过各种场景下的 map 操作实际示例,讲解了 Go 中的 map 关键字。