This question already has an answer here:
How the slice is enlarged by append? Is the capacity always doubled?

(1个答案)


1年前关闭。




在服务器上运行示例The Go Tour(当前在1.12.7版上),如果新的 slice 长度大于当前支持数组的长度,我发现 slice 的容量将增加一倍,达到下一个2的幂。

如果我在计算机上运行相同的程序(Windows上为1.10.3版),则 slice 容量将更改为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)
}

最佳答案

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))
    }
}

显示上述情况的游乐场:

https://play.golang.org/p/OKtCFskbp2t

关于go - Go slice容量在追加时如何变化? [复制],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57100525/

10-12 00:21
查看更多