Golang中使用Map来存储一系列的key/value键值对,可以使用key来对value进行操作(增、删、改、查),map的零值为nil。
介绍
Map
的 key
只能为可使用 ==
运算符的值类型(字符串、数字、bool、数组),value 可以为任何类型。
说明:
key
需要支持等值运算
map
是无序的,每次遍历的顺序可能都不一样
- 源码:
runtime/map.go
- 源码通过
fastrand
生成随机数,选择一个桶位置作为起始bucket进行遍历迭代
- bucket 编译好,开始遍历 overflow buckets
- 相关函数
map
的负载因子是 6.5,平衡时间和空间,参考
- 负载因子(load factor),用于衡量当前哈希表中空间占用率的核心指标
- 当 B(bucket)平均每个存储的元素大于或等于 6.5 时,就会触发扩容行为
- Java HashMap 的负载因子为何默认是 0.75
map
的扩缩容的主要区别在于 hmap.B
的容量大小改变
map
删除元素时不释放内存空间,可以通过创建一个新的 map
并从旧的 map
中复制元素
map
是线程不安全的,sync.Map 是线程安全的
- map 可以使用
reflect.DeepEqual
比较
- 读取方式,原型包括
mapaccess1/mapaccess2/mapaccess1_xxx/mapaccess2_xxx
,使用:
v := m[i]
v, ok := m[i]
示例
基础使用
package main
import (
"fmt"
)
func ExampleMap() {
// 声明
var ages map[string]int
fmt.Printf("%T %#v\n", ages, ages)
fmt.Println(ages == nil) // 默认值为 nil
// 字面值
// ages = map[string]int{} // 定义空map
ages = map[string]int{"xiaowang": 18} // 定义空map
ages["xiaoming"] = 23
fmt.Printf("%T %#v\n", ages, ages)
//ages = make(map[string]int)
//fmt.Printf("%T %#v\n", ages, ages) //map[string]int map[string]int{}
// 操作
fmt.Println(ages["xiaoming"])
fmt.Println(ages["xianbin"]) // 不存在该值,默认为 int 的零值 0
// 查
age, ok := ages["xianbin"] // 判断是否存在,返回两个值,如存在获取 age, true,不存在 0, false
if ok {
fmt.Println(age)
} else {
fmt.Println("not exist")
}
if age, ok := ages["xianbin"]; ok {
fmt.Println(age)
} else {
fmt.Println("not exist")
}
// 改
ages["xiaoming"] = 22
// 增
ages["xianbin"] = 18
fmt.Printf("%T %#v\n", ages, ages)
// 删除
delete(ages, "xianbin")
delete(ages, "bin") // 删除key不存在的值
fmt.Printf("%T %#v\n", ages, ages)
// 获取长度
fmt.Println(len(ages))
// 遍历数组
delete(ages, "xiaoming")
for k, v := range ages {
fmt.Println(k, v)
}
// Output:
//map[string]int map[string]int(nil)
//true
//map[string]int map[string]int{"xiaoming":23, "xiaowang":18}
//23
//0
//not exist
//not exist
//map[string]int map[string]int{"xianbin":18, "xiaoming":22, "xiaowang":18}
//map[string]int map[string]int{"xiaoming":22, "xiaowang":18}
//2
//xiaowang 18
}
func main() {
ExampleMap()
}
说明:
- range map 获取值的情况:
- 获取key, value:
k, v := range map
- 仅获取key:
k := range map
- 初始化如
{"url": ["seo1", "seo2"]}
格式 map:map[string][]string{}
复合使用
package main
import (
"fmt"
)
func ExampleMap() {
// 声明
var ages map[string]int
fmt.Printf("%T %#v\n", ages, ages)
fmt.Println(ages == nil) // 默认值为 nil
// 字面值
// ages = map[string]int{} // 定义空map
ages = map[string]int{"xiaowang": 18} // 定义空map
ages["xiaoming"] = 23
fmt.Printf("%T %#v\n", ages, ages)
//ages = make(map[string]int)
//fmt.Printf("%T %#v\n", ages, ages) //map[string]int map[string]int{}
// 操作
fmt.Println(ages["xiaoming"])
fmt.Println(ages["xianbin"]) // 不存在该值,默认为 int 的零值 0
// 查
age, ok := ages["xianbin"] // 判断是否存在,返回两个值,如存在获取 age, true,不存在 0, false
if ok {
fmt.Println(age)
} else {
fmt.Println("not exist")
}
if age, ok := ages["xianbin"]; ok {
fmt.Println(age)
} else {
fmt.Println("not exist")
}
// 改
ages["xiaoming"] = 22
// 增
ages["xianbin"] = 18
fmt.Printf("%T %#v\n", ages, ages)
// 删除
delete(ages, "xianbin")
delete(ages, "bin") // 删除key不存在的值
fmt.Printf("%T %#v\n", ages, ages)
// 获取长度
fmt.Println(len(ages))
// 遍历数组
delete(ages, "xiaoming")
for k, v := range ages {
fmt.Println(k, v)
}
// Output:
//map[string]int map[string]int(nil)
//true
//map[string]int map[string]int{"xiaoming":23, "xiaowang":18}
//23
//0
//not exist
//not exist
//map[string]int map[string]int{"xianbin":18, "xiaoming":22, "xiaowang":18}
//map[string]int map[string]int{"xiaoming":22, "xiaowang":18}
//2
//xiaowang 18
}
func main() {
ExampleMap()
}
合并
package main
import (
"fmt"
"golang.org/x/exp/maps"
)
func main() {
ages1 := map[string]int{"xiaowang": 18}
ages2 := map[string]int{"xiaoming": 19}
// Print the map before merging
fmt.Println("The age1 Map: ", ages1)
fmt.Println("The age2 Map: ", ages2)
maps.Copy(ages1, ages2)
fmt.Println("The merged Map is: ", ages1)
}