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
关键字。