为了账号安全,请及时绑定邮箱和手机立即绑定

Go 切片容量在追加时如何变化?

Go 切片容量在追加时如何变化?

Go
浮云间 2023-07-04 17:07:38
在服务器上运行示例The Go Tour(当前版本为 1.12.7),我发现如果新切片长度大于当前支持数组的长度,则切片的容量会加倍到 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 mainimport "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)}
查看完整描述

2 回答

?
杨__羊羊

TA贡献1943条经验 获得超7个赞

这取决于数组中存储的元素的大小


可以在这里看到实现:


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


查看完整回答
反对 回复 2023-07-04
?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

根据Go slice内部的信息,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

}


查看完整回答
反对 回复 2023-07-04
  • 2 回答
  • 0 关注
  • 116 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信