内容简介:go是宣扬实用主义的语言,很多时候都把c中的最佳实践直接规定成语法了。其中之一就是slice,简单但是非常容易踩坑。先看一个小例子:在这个小例子中,原本是希望将
go是宣扬实用主义的语言,很多时候都把c中的最佳实践直接规定成语法了。其中之一就是slice,简单但是非常容易踩坑。
先看一个小例子:
func main() { a := make([]int, 2, 2) a[0], a[1] = 1, 2 b := append(a[0:1], 3) c := append(a[1:2], 4) fmt.Println(b,c) }
在这个小例子中,原本是希望将 a[0:1]
作为b的前缀,然后追加上3;将 a[1:2]
作为c的前缀,然后追加上4。但实际上输出结果并不是原本期望的 [1 3] [2 4]
,而变成了 [1 3] [3 4]
。这是为什么呢?
我们知道数据结构中数组是非常高效的,可以直接寻址,但是有个缺陷,难以扩容。所以slice被设计为指向数组的指针,在需要扩容时,会将底层数组上的值复制到一个更大的数组上然后指向这个新数组。
slice有个特性是允许多个slice指向同一个底层数组,这是一个有用的特性,在很多场景下都能通过这个特性实现 no copy 而提高效率。但共享同时意味着不安全。b在追加3时实际上覆盖了 a[1]
,导致c变成了 [3 4]
。
怎么解决呢?防止共享数据的出现问题需要注意两条,只读和复制,或者统一归纳为不可变。
写法1,make出一个新slice,然后先copy前缀到新数组上再追加:
func main() { a := make([]int, 2, 2) a[0], a[1] = 1, 2 b := make([]int, 1) copy(b, a[0:1]) b = append(b, 3) c := make([]int, 1) copy(c, a[1:2]) c = append(c, 4) fmt.Println(b, c) }
写法2,利用 go 中slice的一个小众语法, a[0:1:1] (源[起始index,终止index,cap终止index])
,强迫追加时复制到新数组。
func main() { a := make([]int, 2, 2) a[0], a[1] = 1, 2 b := append(a[0:1:1], 3) c := append(a[1:2:2], 4) fmt.Println(b, c) }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Chrome 75 Beta 发布,Web 共享功能支持共享文件
- ios – 如何使用OpenGL ES共享组在iPad上共享屏幕镜像的渲染缓冲区?
- nfs 共享实验
- 进程间通信---共享内存
- “伪共享” 凌乱记
- 共享测试的团队介绍
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning Java Objects中文版从概念到代码
巴克 / 万波 / 人民邮电出版社 / 2007-1 / 78.00元
《Beginning Java Objects中文版从概念到代码(第2版)》是关于软件对象和Java的,但并不是纯粹地介绍Java语言,而是强调如何从对象模型转换到功能完整的Java应用程序。书中讲述了对象基础、对象建模和模型的实现。《Beginning Java Objects中文版从概念到代码(第2版)》除了用学生注册系统(SRS)示例贯穿全书之外,还在附录中给出三个附加的案例,这些案例是每章......一起来看看 《Beginning Java Objects中文版从概念到代码》 这本书的介绍吧!