【问题标题】:Not double the array size when append追加时不将数组大小加倍
【发布时间】:2021-01-08 15:30:50
【问题描述】:

对于

package main

import "fmt"

func main() {


    b := make([]int, 1, 5)  
    printSlice("b", b[:cap(b)])
    
    b2 := append(b, 1)
    b3 := append(b2, 1)
    b4 := append(b3, 1)
    b5 := append(b4, 1)
    
    printSlice("bbbb", b5[:cap(b5)])
    
    b6 := append(b5, 1)
    
    printSlice("bbbb", b6[:cap(b6)])
    
    
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

结果是

b len=5 cap=5 [0 0 0 0 0]
bbbb len=5 cap=5 [0 1 1 1 1]
bbbb len=10 cap=10 [0 1 1 1 1 1 0 0 0 0]

看起来最后一个 append 是底层数组大小的两倍,有没有办法说它的大小为 6?

【问题讨论】:

  • 如果您需要特定容量,您可以切片或分配您想要的容量。 append 在一般情况下效率最高。
  • 这里提出了一个可能的解决方案:github.com/golang/go/issues/41551

标签: go slice


【解决方案1】:

如果您使用内置 append(),则无法控制结果容量。它没有记录容量增长策略,因此没有什么可期待的(除了被附加的元素将适合它)。考虑到未来的增长(以减少未来的分配),它通常会分配比需要更多的钱。 Spec: Appending to and copying slices 列出了您对 append() 的所有“保证”以及生成的切片容量:

如果s 的容量不足以容纳附加值,append 会分配一个新的、足够大的底层数组,以适应现有的切片元素和附加值。否则,append 会重新使用底层数组。

如果你想控制结果切片的容量,你必须自己分配它,复制旧切片并附加到新切片,例如:

b6 := make([]int, len(b5), len(b5)+1)
copy(b6, b5)
b6 = append(b6, 1)

然后输出将是(在Go Playground上试试):

b len=5 cap=5 [0 0 0 0 0]
bbbb len=5 cap=5 [0 1 1 1 1]
bbbb len=6 cap=6 [0 1 1 1 1 1]

如您所见,需要完成“很多”工作:要创建新切片(带有支持数组),复制旧切片,然后进行追加操作(这可以通过创建新切片来优化,例如make([]int, len(b5)+1),那么最后的追加就是b6[len(b6-1] = 1)。当附加单个元素时一直执行这些操作将是一种浪费,这就是为什么append() 分配更多,因此不必一直执行。

查看相关问题:

Go slices - capacity/length?

Golang slice append vs assign performance

Insert a value in a slice at a given index

Concatenate two slices in Go

【讨论】:

    【解决方案2】:

    有没有办法把它做成 6 号?

    没有。追加做它做的事。但是没有什么能阻止您提供具有所需上限的切片。

    【讨论】:

      猜你喜欢
      • 2014-04-10
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 1970-01-01
      • 2015-09-21
      • 2020-12-29
      • 2014-07-01
      相关资源
      最近更新 更多