0

Go之slice陷阱

 2 years ago
source link: https://davidchan0519.github.io/2019/08/23/golang-slice-misunderstanding/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Go之slice陷阱

Posted on

2019-08-23

| Views: 139

这个问题隐藏的很深,稍不注意就掉入坑中,并且定位起来耗时费力。

数组(array):
var a [...]int{1,2,3}
切片(slice):
var b [ ]int{1,2}

注意上述数组和切片的不同之处。

下面通过一段示例代码,我们来仔细讨论下slice的陷阱,稍有不慎,就会掉入坑中。

a := []int{0}     /* [0]          */
a = append(a, 0) /* [0, 0] */
b := a[:] /* [0, 0] */
a = append(a, 2) /* [0, 0, 2] */
b = append(b, 1) /* [0, 0, 1] */
fmt.Println("[2]:",a[2]) /* 2 <- 对的 */

// 一样的代码,只是以一个稍大的 slice 开始, c := []int{0, 0} /* [0, 0] */
c = append(c, 0) /* [0, 0, 0] */
d := c[:] /* [0, 0, 0] */
c = append(c, 2) /* [0, 0, 0, 2] */
d = append(d, 1) /* [0, 0, 0, 1] */
fmt.Println("[3]:",c[3]) /* ??? ,正确答案是1 */

为什么a2的值为2,c3的值为1呢?

原因在与,slice的底层空间,append操作后并非永远是线性增长的,当达到一定的阀值后,slice会重新开辟新的空间(重新申请新的内存)。这样之前本来共享底层空间的两个slice,在其中一个重新开辟新的空间后,就不再共享空间了,也就不再互相影响了。

例如代码中的slice a和b,a在append 2后,就开辟了新的空间,b在append 1操作后也开辟了新的空间,故b的append操作不会影响到a。

但是c和d则不一样,c在进行append 2后,仍然在使用原来的底层空间,d在append 1后也在使用原来的底层空间,故c的操作会被d的append操作覆盖掉。

什么时候slice会开辟新的空间,这是由go的底层算法决定的。没有办法人为控制。

怎么避免这类问题呢?避免slice共享同一块底层空间,尤其是当slice不断增长的情况下。否则你会遇到很多莫名其妙的问题。

您的鼓励是我持之以恒的动力

Related Issues not found

Please contact @DavidChan0519 to initialize the comment


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK