1.定义
一个拥有键值对元素的无序集合。
map 的定义如下map[KeyType]ValueType
其中 KeyType 表示键的类型, ValueType 表示值的类型。
注意:
键的类型必须是可以用操作符==来进行比较的数据类型。
golang的映射在底层是用哈希表实现的。
map 类型的零值是nil。
map 元素不是一个变量, 不可以获取它的地址。我们无法获取map元素的地址的一个原因是map的增长可能会导致已有元素被重新散列到新的存储位置,这样就可能使得获得的地址无效。
2.创建和初始化
使用字面量来新建一个带初始化键值对元素的字典
ages := map[string]int{
"a": 1,
"b": 2,
}
使用内置函数make来创建一个mapmake(map[KeyTyep]ValueType, [cap])
其中cap表示map的容量,该参数虽然不是必须的,但是我们应该在初始化map的时候就为其指定一个合适的容量。
func main() {
m := make(map[string]int, 5)
m["a"] = 1
m["b"] = 2
m["c"] = 3
m["d"] = 4
fmt.Printf("m: %#v\n", m)
m["e"] = 5
fmt.Printf("m: %#v\n", m)
m["f"] = 6 // 当长度超过 cap时, 长度会增加。
fmt.Printf("m: %#v\n", m)
}
新的空的map,另一种表达式为 make[string]int{}
设置元素之前,必须初始化map.
map类型的零值是nil, 也就是说,没有引用任何散列表。
var ages map[string] int
fmt.Println(ages == nil) // true
fmt.Println(len(ages) == 0) // true
大多数的map操作是都可以安全地在map的零值nil上进行, 包括查找元素, 删除元素, 获取map元素个数, 执行range循环, 因为这和空map的行为一致。但是向零值map中设置元素会导致错误:ages["a"] = 1 // 宕机: 会报错
所以, 设置元素之前, 必须初始化map.
func main() {
var ages map[string]int
fmt.Println(ages == nil) // true
fmt.Println(len(ages) == 0) // true
ages = make(map[string]int)
fmt.Println(ages != nil) // true
fmt.Println(len(ages) == 0) // true
ages["a"] = 1
fmt.Println(len(ages) == 1) // true
}
查找与遍历
查找某个key 是否在map中
age, ok := ages["bob"]
if !ok {
/*"bob" 不是字典中的键*/
}
或者
if age, ok := ages["bob"]; !ok {
/*"bob" 不是字典中的键*/
}
遍历
for name, age := range ages {
fmt.Printf("%s\t%d\n", name, ages)
}
删除元素
使用内置函数 delete 来从字典中根据键值移除一个元素。
delete(ages, "a") // 移除元素ages["a"]
如果 “a” 这个键不存在,那么这个调用将什么都不会发生,也不会有什么副作用。但是如果传入的映射的变量的值为 nil,该调用将导致程序抛出异常(panic)。
比较
和slice 一样, map不可以比较。
唯一合法的比较是通过 nil 进行比较。
为了判断两个map是否拥有相同的键和值, 需要循环比较
func equalMap(x, y map[string]int) bool {
if len(x) != len(y) {
return false
}
for xk, xv := range x {
if yv, ok := y[xk]; !ok || xv != yv {
return false
}
}
return true
}
集合
函数间传递映射
在函数间传递映射并不会制造出该映射的一个副本。实际上,当传递映射给一个函数,并对 这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改
func moveItem(m map[string]int, key string) {
delete(m, key)
}
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
}
for k, v := range m{
fmt.Printf("(%v, %v)\n", k, v)
}
fmt.Println("----------------")
moveItem(m, "c")
for k, v := range m{
fmt.Printf("(%v, %v)\n", k, v)
}
}
源码解析
代码片段
参考资料
《Go in action》
《The Go Programming Language》
https://www.liwenzhou.com/posts/Go/08_map/
https://www.cnblogs.com/sparkdev/p/10749542.html