jee said
Go语言Map使用指南
Map是Go语言中重要的键值对数据结构,类似于其他语言中的字典或哈希表。Map提供了快速的查找、插入和删除操作。
Map创建
基本创建方式
// 方式1:使用make函数
m1 := make(map[string]int)
// 方式2:使用字面量
m2 := map[string]int{
"apple": 5,
"banana": 3,
"orange": 8,
}
// 方式3:空Map
m3 := map[string]int{}Map初始化
// 创建带容量的Map
m := make(map[string]int, 100)
// 初始化多个键值对
user := map[string]string{
"name": "张三",
"email": "zhangsan@example.com",
"city": "北京",
}Map操作
添加和修改
m := make(map[string]int)
// 添加键值对
m["apple"] = 5
m["banana"] = 3
// 修改已有键
m["apple"] = 10
fmt.Println(m) // map[apple:10 banana:3]读取值
m := map[string]int{"apple": 5, "banana": 3}
// 读取值
value := m["apple"]
fmt.Println(value) // 5
// 检查键是否存在
value, exists := m["orange"]
if exists {
fmt.Println("orange存在,值为:", value)
} else {
fmt.Println("orange不存在")
}删除元素
m := map[string]int{"apple": 5, "banana": 3, "orange": 8}
// 删除键
delete(m, "banana")
fmt.Println(m) // map[apple:5 orange:8]获取长度
m := map[string]int{"apple": 5, "banana": 3, "orange": 8}
fmt.Println(len(m)) // 3Map遍历
遍历键值对
m := map[string]int{"apple": 5, "banana": 3, "orange": 8}
for key, value := range m {
fmt.Printf("%s: %d\n", key, value)
}
// 输出顺序不确定只遍历键
m := map[string]int{"apple": 5, "banana": 3, "orange": 8}
for key := range m {
fmt.Println(key)
}只遍历值
m := map[string]int{"apple": 5, "banana": 3, "orange": 8}
for _, value := range m {
fmt.Println(value)
}Map排序
Go语言的Map是无序的,如果需要有序输出,需要对键进行排序。
按键排序
import "sort"
m := map[string]int{"apple": 5, "banana": 3, "orange": 8}
// 获取所有键并排序
keys := make([]string, 0, len(m))
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
// 按排序后的键遍历
for _, key := range keys {
fmt.Printf("%s: %d\n", key, m[key])
}按值排序
type KeyValue struct {
Key string
Value int
}
func main() {
m := map[string]int{"apple": 5, "banana": 3, "orange": 8}
// 转换为切片
kvs := make([]KeyValue, 0, len(m))
for key, value := range m {
kvs = append(kvs, KeyValue{Key: key, Value: value})
}
// 按值排序
sort.Slice(kvs, func(i, j int) bool {
return kvs[i].Value > kvs[j].Value
})
// 输出
for _, kv := range kvs {
fmt.Printf("%s: %d\n", kv.Key, kv.Value)
}
}Map作为集合
Go语言没有内置的集合类型,但可以用Map模拟。
使用Map作为集合
// 创建集合
set := make(map[string]bool)
// 添加元素
set["apple"] = true
set["banana"] = true
set["orange"] = true
// 检查元素是否存在
if set["apple"] {
fmt.Println("apple在集合中")
}
// 删除元素
delete(set, "banana")
// 获取集合大小
fmt.Println(len(set)) // 2集合操作
// 并集
func union(set1, set2 map[string]bool) map[string]bool {
result := make(map[string]bool)
for key := range set1 {
result[key] = true
}
for key := range set2 {
result[key] = true
}
return result
}
// 交集
func intersection(set1, set2 map[string]bool) map[string]bool {
result := make(map[string]bool)
for key := range set1 {
if set2[key] {
result[key] = true
}
}
return result
}并发安全Map
Go语言的Map不是并发安全的,多个goroutine同时读写会导致panic。
使用sync.Map
var m sync.Map
// goroutine 1
go func() {
m.Store("key1", "value1")
}()
// goroutine 2
go func() {
m.Store("key2", "value2")
}()
// 读取值
if value, ok := m.Load("key1"); ok {
fmt.Println(value)
}使用Mutex保护
type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func NewSafeMap() *SafeMap {
return &SafeMap{
m: make(map[string]int),
}
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mu.RLock()
defer sm.mu.RUnlock()
value, ok := sm.m[key]
return value, ok
}
func (sm *SafeMap) Set(key string, value int) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.m[key] = value
}Map嵌套
// 嵌套Map
users := map[string]map[string]int{
"user1": {
"score": 100,
"level": 5,
},
"user2": {
"score": 90,
"level": 4,
},
}
// 访问嵌套值
fmt.Println(users["user1"]["score"]) // 100
// 修改嵌套值
users["user2"]["level"] = 10Map与JSON
Map转JSON
import "encoding/json"
m := map[string]interface{}{
"name": "张三",
"age": 30,
"email": "zhangsan@example.com",
}
data, _ := json.Marshal(m)
fmt.Println(string(data))
// {"age":30,"email":"zhangsan@example.com","name":"张三"}JSON转Map
jsonData := `{"name":"张三","age":30,"email":"zhangsan@example.com"}`
var m map[string]interface{}
json.Unmarshal([]byte(jsonData), &m)
fmt.Printf("%+v\n", m)
// map[age:30 email:zhangsan@example.com name:张三]最佳实践
- 使用make创建Map:避免nil Map的panic
- 检查键是否存在:使用两个返回值检查
- 预分配容量:当知道大小时预分配可以提高性能
- 并发场景使用sync.Map:多个goroutine访问时使用并发安全Map
- 注意Map遍历顺序:Map的遍历顺序是不确定的
总结
Go语言的Map提供了高效的键值对存储和查找功能。通过合理使用Map,可以简化很多编程任务。掌握Map的使用对于编写高效的Go程序非常重要。