这个问题隐藏的很深,稍不注意就掉入坑中,并且定位起来耗时费力。
数组(array):
1 | var a [...]int{1,2,3} |
切片(slice):
1 | var b [ ]int{1,2} |
注意上述数组和切片的不同之处。
下面通过一段示例代码,我们来仔细讨论下slice的陷阱,稍有不慎,就会掉入坑中。
1 | a := []int{0} /* [0] */ |
输出:
原因在与,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不断增长的情况下。否则你会遇到很多莫名其妙的问题。