前言
本文主要讲述使用map可能会遇到的几个问题,希望能帮到大家!
1.创建map的两种方式
func main() {
// 1.直接声明并初始化
map1 := map[string]int{"aa": 1, "bb": 2}
map1["cc"] = 3
fmt.Println(map1) // [aa:1 bb:2 cc:3]
// 2.通过make关键字
map2 := make(map[string]int)
map2["aa"] = 1
fmt.Println(map2)
}
可能会有人奇怪为什么通过var map1 map[string]int 声明一个map后,无法添加数据。
这是因为var关键字只声明了map,并没有初始化它,相当于创建了一个指针(即分配了指针的内存空间),但是没有分配指针指向的空间(存储数据的空间),而make关键字就是两个都分配。
2.map结构体成员不能修改问题
这是因为如果你想实现赋值,即x = y,则必须知道x的内存地址。但是Golang中的map的value本身是不可寻址的,由于value不可寻址,所以像上面那样赋值就会出错。
解决办法也很简单,加上指针即可,因为加上指针,value的地址就知道了,也就能赋值了。
参考:Go struct 类型的 map 结构体成员不能修改的问题
3.map的并发问题
当在单个协程中读写map时,并不会出现什么问题, 但是如果多个协程并发访问一个map,有可能会导致程序退出,并打印下面的错误信息: fatal error: concurrent map read and map write。 当并发的协程数比较大时,遇到的概率较大
下面是一个栗子:
// 这种情况下map是不安全的
func readMap(Map map[int]int, key int) int{
fmt.Println(key)
return Map[key]
}
func writeMap(Map map[int]int, key int, value int){
Map[key] = value
}
func unsafeMap(){
Map := make(map[int]int)
for i:=0; i<1000; i++{
// 每循环一次,创建两个goroutine线程
go writeMap(Map, i, i)
go readMap(Map, i)
}
}
func main() {
unsafeMap()
}
map的并发可以通过加锁解决
type SafeMap struct {
sync.RWMutex
Map map[int]int
}
func newSafeMap(size int) *SafeMap {
sm := new(SafeMap)
sm.Map = make(map[int]int, size)
return sm
}
func (sm *SafeMap) readSafeMap(key int) int {
// 读写锁, 读不会阻塞,写会阻塞
sm.RLock()
value := sm.Map[key]
fmt.Println(value)
sm.RUnlock()
return value
}
func (sm *SafeMap) writeSafeMap(key int, value int) {
// 互斥锁, 读和写都会阻塞
sm.Lock()
sm.Map[key] = value
sm.Unlock()
}
func viewSafeMap() {
safeMap := newSafeMap(10)
for i := 0; i < 1000; i++{
go safeMap.writeSafeMap(i, i)
go safeMap.readSafeMap(i)
}
}
func main() {
viewSafeMap()
}
4.比较两个 map 是否相等
可通过 reflect.DeepEqual 比较,适用于 slice 和 struct,详情请戳:mozillazg.com/2014/11/go-…