在服务器(当前版本为1.12.7)上运行示例The Go Tour时,如果新的切片长度大于当前支持阵列的长度,我发现切片的容量加倍到下一个2的幂。
如果我在计算机上运行相同的程序(Windows上为1.10.3版),则切片容量将更改为下一个2的倍数。
为什么它们不同?是因为Go版本还是运行时实现?容量变化确定吗?
远程服务器上的输出是
len=0 cap=0 []
len=1 cap=2 [0]
len=2 cap=2 [0 1]
len=5 cap=8 [0 1 2 3 4]
本地计算机上的输出是
len=0 cap=0 []
len=1 cap=1 [0]
len=2 cap=2 [0 1]
len=5 cap=6 [0 1 2 3 4]
这是参考代码
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// append works on nil slices.
s = append(s, 0)
printSlice(s)
// The slice grows as needed.
s = append(s, 1)
printSlice(s)
// We can add more than one element at a time.
s = append(s, 2, 3, 4)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
答案 0 :(得分:0)
TL; DR:这取决于存储在数组中的元素的大小
实现可以在这里看到:
https://github.com/golang/go/blob/master/src/runtime/slice.go
但是,正如您所看到的,回顾历史并不能一直保持不变。
这也许也可以解释您在不同版本的Go上可能会注意到的区别。
进行一些测试表明,大小为0的结构如何将容量仅增加1个元素,并且每次增长时int或string都将重复,而每次增长时3字节的结构“大约”会翻倍。
您可以使用不同的类型来执行这样的代码,以查看实际情况:
arr := []struct{}{}
oldCap := 0
for i := 0; i < 100; i++ {
arr = append(arr, struct{}{})
if cap(arr) != oldCap {
oldCap = cap(arr)
fmt.Println("arr", cap(arr))
}
}
显示上述情况的操场:
答案 1 :(得分:-1)
根据Go slice internal的信息,append的实现行为如下。
它只是(len(source slice) + len(new data)) * 2
func AppendByte(slice []byte, data ...byte) []byte {
m := len(slice)
n := m + len(data)
if n > cap(slice) { // if necessary, reallocate
// allocate double what's needed, for future growth.
newSlice := make([]byte, (n+1)*2)
copy(newSlice, slice)
slice = newSlice
}
slice = slice[0:n]
copy(slice[m:n], data)
return slice
}