go - 追加时不将数组大小加倍
问题描述
为了
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]
看起来最后一个追加是基础数组大小的两倍,有没有办法说它的大小为 6?
解决方案
如果您使用的是内置的,则无法控制结果容量append()
。它没有记录容量增长策略,所以没有什么可期待的(除了被附加的元素将适合它)。考虑到未来的增长(以减少未来的分配),它通常会分配比需要更多的钱。规范:附加和复制切片列出了您需要重新保护的所有“保证”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()
分配更多因此不必一直执行的原因。
查看相关问题:
推荐阅读
- python - 用于在 Excel 中导出的嵌套字典顺序或 pandas 列的顺序
- sqlite - React native sqlite 如何在 Flatlist 上从数据库中呈现数据(JSON 类型)?
- java - NoClassDefFoundError 如果在主方法之外调用类
- angular - 访问 WebApi 时不允许使用 Angular 5 HTTP get 方法
- postgresql - 在数据目录从 PostgreSQL 8.4.8 升级到 PostgreSQL 9.5.2 期间,日志(很少)出现两次
- c# - 在 Visual Studio 中随机化用户代理 GeckoFX
- synchronization - Netdrive 和同步文件夹 (Nextcloud) 之间的 MS Office 锁定文件(所有者文件)行为不同
- javascript - 我可以发送文件上传的默认值吗?
- angular-material - 'mat-toolbar' 不是已知元素 - Angular 5
- php - 我有两个包含重复值和唯一值的表。我不需要两个表中的重复值,我只需要唯一值