当前位置: 首页 > 科技观察

Go语言Map复制陷阱,Slice更新陷阱

时间:2023-03-12 14:17:37 科技观察

map可以复制吗?事实上,地图是不可复制的。如果要复制一个地图,唯一的办法就是循环赋值,像这样(map[string]int)//Copyfromtheoriginalmaptothetargetmapforkey,value:=rangeoriginalMap{targetMap[key]=value}ifinmap有指针,还要考虑deepcopyoriginalMap:=make(map[string]*int)的过程varnumint=1originalMap["one"]=&num//CreatethetargetmaptargetMap:=make(map[string]*int)//Copyfromtheoriginalmaptothetargetmapforkey,value:=rangeoriginalMap{vartmpNumint=*valuetargetMap[key]=&tmpNum}如果要更新value在map中,可以赋值map["one"]=1,但是如果value是结构体,可以直接替换结构体,但是结构体里面的值是不能更新的originalMap:=make(map[string]Person)originalMap["minibear2333"]=Person{age:26}originalMap["minibear2333"].age=5你可以试试源函数[脚注1]会报这个错误"CannotassigntooriginalMap["minibear2333"].age"问题链接issue-3117[脚注2],ianlancetaylor[脚注3]的回答解释得很好。简单来说就是Map不是并发安全的结构,因此它在结构中的值不能被修改。如果不能修改当前的表格,有两种选择,1.修改原来的设计;2.想办法让Membervariables中的map可以修改,因为懒得改这个结构,所以选择了方法2或者创建一个临时变量然后复制一份,像这样tmp:=m["foo"]tmp.x=4m["foo"]=tmp或者直接用指针比较方便。originalPointMap:=make(map[string]*Person)originalPointMap["minibear2333"]=&Person{age:26}originalPointMap["minibear2333"].age=5slice有一种复制陷阱切片的方法,速度更快slice3:=slice2[:]但是有一个致命的缺点,就是浅拷贝,slice3和slice2是同一个slice,无论哪个改变,另一个都会改变。可能是你还不能加深理解。这一段func(b*Buffer)Bytes()[]byte{returnb.buf[b.off:]}出现在源码bytes.buf[footnote4]我们读取输入流的时候,很容易这样的问题出现在下面的例子中,使用abc模拟读取内容,修改返回值buffer:=bytes.NewBuffer(make([]byte,0,100))buffer.Write([]byte("abc"))resBytes:=buffer.Bytes()fmt.Printf("%s\n",resBytes)resBytes[0]='d'fmt.Printf("%s\n",resBytes)fmt.Printf("%s\n",buffer.Bytes())输出,可以看出会影响到原来的分片内容abcdbcdbc这种情况在并发使用的时候特别危险,尤其是流式读写的时候容易出现最后一个处理不上的情况完成,接下来的数据覆盖乱写脚注直接点击阅读原文跳转试试源码函数updateMapValue:https://github.com/golang-minibear2333/golang/blob/master/2.func-containers/2.4-map/map1.go#L89问题3117:https://github.com/golang/go/issues/3117ianlancetaylor:https://github.com/golang/go/issues/3117#issuecomment-430632750源代码https://github.com/golang/go/blob/cb4cd9e17753b5cd8ee4cd5b1f23d46241b485f1/src/bytes/buffer.go#L54本文转载自微信♂“机智程序员熊”,可通过以下二维码关注。转载本文请联系机智的程序员小熊公众号。