大家好,我是建宇。Go1.18将在几周后(3月)发布。之前我们已经更新了几个新的版本特性,今天给大家带来一个新的优化类,是和strings和bytes标准库相关的。背景想更快速的拷贝在日常编程中,经常会拷贝byte[]byte。需要写如下代码:dup:=make([]byte,len(data))copy(dup,data)@IliaCholy觉得这样太麻烦了,毕竟每次都要写,或者你可以自己打包如下函数://ClonereturnsacopyofbfuncClone(b[]byte)[]byte{b2:=make([]byte,len(b))copy(b2,b)returnb2为此我想添加一个快捷方式,但这显然是站不住脚的。熟悉语法的同学会发现有个现成的方法:b2:=append([]byte(nil),b...)一行就可以达到效果,甚至更快,因为分配的切片不是初始化为零值。复制将共享内存。很多Go开发者,在编写复制切片(Slice)的应用程序时,会发现复制的切片s1和原来的s0存在内存连接。本质原因是底层数据结构。会导致很多隐藏的问题。示例代码如下:import("fmt""reflect""unsafe")funcmain(){s0:="我脑子炸了"s1:=s0[:3]s0h:=(*reflect.StringHeader)(unsafe.Pointer(&s0))s1h:=(*reflect.StringHeader)(unsafe.Pointer(&s1))fmt.Printf("Len等于:%t\n",s0h.Len==s1h.Len)fmt.Printf("Dataisequal:%t\n",s0h.Data==s1h.Data)}从上面的程序来看,你认为变量s0和s1的Lens是否相等?数据是否相等?输出如下:Len等于:falseData等于:true乍一看好像没问题。Len不相等,毕竟是索引复制的。但是Data其实是相等的,为什么这是Go中的一个bug呢?这其实和Go的底层数据结构String和Slice有关。比如String的运行时表现就是StringHeader。其底层结构如下:typeStringHeaderstruct{DatauintptrLenint}Data:指向具体的底层数组。Len:表示字符串切片的长度。关键在于Data,它本质上是一个指向底层数据的指针地址,所以复制的时候,也会复制。造成不必要的复制和“脏”数据,造成各种奇怪的BUG。这个问题是新特性的痛点。新特性Go1.18的新特性中,strings和bytes增加了一个Clone方法来解决上面提到的两个问题。源码如下:funcClone(sstring)string{iflen(s)==0{return""}b:=make([]byte,len(s))copy(b,s)return*(*string)(unsafe.Pointer(&b))}使用复制函数复制原始字符串得到新的[]byte数据。使用*(*string)(unsafe.Pointer(&b))进行指针操作,实现byte到string的零内存拷贝转换。至此,后台的两个问题已经很巧妙的解决了。您不必一直重复类似的代码。总结一直以来,Go中的string和slice因为底层的数组指向和扩缩容机制而备受争议。最后还给出了公众号之前介绍的一些“坑”。有兴趣的读者可以看看。这次1.18新方法更新有一定的作用,学习中也可以清楚的知道Clone的作用和定义,牢记在心。你的项目中有类似的代码吗?如有任何问题,欢迎在评论区反馈交流。最好的关系是相互成就。您的好评是创作炸鱼最大的动力。感谢您的支持。文章持续更新中。可以微信搜索【脑补炸鱼】阅读。本文已收录在GitHubgithub.com/eddycjy/blog中。学习Go语言可以看Go学习地图和路线。欢迎星星提醒。以前推荐Go切片导致内存泄露,被坑过两次!Go切片的问题争论了一下午!参考bytes、strings:addClone[test:addtestthatwedon'toptimizestring([]byte(string))](https://github.com/golang/go/...)建议:提供stdlibpkgClone函数可在不共享内存的情况下有效地复制字符串
