Go源码分析:map
map使用要点
- map的存储是将多个key/value对分散存储在buckets(桶)中,根据key的哈希结果决定放在哪一个桶。
- map在声明之后如果直接赋值key和value会导致panic,但如果只是打印key的value等,会返回value的默认空值,不会报错。
- map的两种初始化方法:(1)make形式(2)字面量形式(如空map则等同于make操作)
- make的第二个参数代表初始化创建map的长度。当长度数字为空时,代表默认长度为0。
- key的类型必须是可比较的。
- map的key有类型限制:slice/map/function不可作为key,value没有类型限制。切片、函数、map是不可比较的。
- 使用delete来移除一个元素,重复移除同一个元素,或者移除不存在的key,都不会报错。delete操作没有返回值。
- map元素不是一个变量,不可以获取它的地址。无法获取map元素的地址一个原因是map的增长可能会导致已有元素被重新散列到新的存储位置,从而使得获取的地址无效。所以,也不能直接通过下标修改value成员。正确的做法是返回整个value,待修改后再设置回去,或者直接使用指针类型。
- 可以使用for...range结构来遍历map中的元素。
- map中元素的迭代顺序是不固定(随机)的。
- 如果想按照某种顺序来遍历map中的元素,那必须显式的对key进行排序。
- map的零值是nil。
- 从值为nil的map上进行查找/删除/len/range操作都是没问题的,但是不可以设置元素key/value,会导致panic。
- 要设置key/value,必须初始化map。
- 通过下标的方式访问map中的元素总是会有值。
- 可以通过ok语法判断一个key是否存在于map中。
- map不可比较,唯一合法的比较就是和nil作比较。
- len会返回map的键值对数量,map结构上不可以进行cap操作。
- 在迭代期间删除或新增键值是安全的,但并发map是不安全的,会存在数据竞争。设计时是从性能损失方面进行考虑,并没有加锁保障并发安全。
- Go语言只支持并发的读取Map。Map被设计为不需要从多个goroutine安全访问,在实际情况下Map可能是某些已经同步的较大数据结构或计算的一部分。因此,要求所有Map操作都互斥将减慢大多数程序的速度,而只会增加少数程序的安全性。即这样设计的目的是为了大多数情况下的效率保证。
- 内容为空的map,与nil是不同的。如map[string]int{}这个内容为空,已初始化,等同于make操作。
- Map在实践中极少成为性能的瓶颈,但是却容易写出并发冲突的程序。这要求进行合理的设计以及进行race检查。