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

Go 中的切片:为什么它允许附加超过容量允许的内容?

Go 中的切片:为什么它允许附加超过容量允许的内容?

Go
不负相思意 2021-09-13 14:20:36
在 Go中制作 a的容量参数slice对我来说没有多大意义。例如,aSlice := make([]int, 2, 2) //a new slice with length and cap both set to 2aSlice = append(aSlice, 1, 2, 3, 4, 5) //append integers 1 through 5fmt.Println("aSlice is: ", aSlice)  //output [0, 0, 1, 2, 3, 4, 5]如果切片允许插入的元素比容量允许的多,为什么我们需要在 make() 函数中设置它?
查看完整描述

2 回答

?
猛跑小猪

TA贡献1858条经验 获得超8个赞

如果内置append()函数有足够大的容量来容纳指定的元素,则内置函数使用指定的切片来追加元素。


但是如果传递的切片不够大,它会分配一个新的、足够大的切片,将元素从传递的切片复制到新切片并将元素附加到新切片。并返回这个新切片。从append()文档中引用:


append 内置函数将元素附加到切片的末尾。如果它有足够的容量,目标将被重新切片以容纳新元素。如果没有,将分配一个新的底层数组。Append 返回更新后的切片。因此有必要将 append 的结果存储在保存切片本身的变量中:


制作切片时,make如果长度和容量相同,可以省略容量,此时默认为指定长度:


// These 2 declarations are equivalent:

s := make([]int, 2, 2)

s := make([]int, 2)

另请注意,append()在切片的最后一个元素之后追加元素。并且上面的切片len(s) == 2在声明之后就已经有了,所以如果你只向它附加 1 个元素,它会导致重新分配,如本例所示:


s := make([]int, 2, 2)

fmt.Println(s, len(s), cap(s))

s = append(s, 1)

fmt.Println(s, len(s), cap(s))

输出:


[0 0] 2 2

[0 0 1] 3 4

所以在你的例子中你应该做的是这样的:


s := make([]int, 0, 10) // Create a slice with length=0 and capacity=10

fmt.Println(s, len(s), cap(s))

s = append(s, 1)

fmt.Println(s, len(s), cap(s))

输出:


[] 0 10

[1] 1 10


查看完整回答
反对 回复 2021-09-13
?
阿晨1998

TA贡献2037条经验 获得超6个赞

它主要是一种优化,它不是唯一的,其他语言中的类似结构也有。

当您追加超过容量时,运行时需要为新元素分配更多内存。这代价高昂,而且还会导致内存碎片。

通过指定容量,运行时预先分配所需的内容,并避免重新分配。但是,如果您事先不知道估计容量或它发生了变化,则不必设置它,运行时会重新分配所需的容量并自行增加容量。


查看完整回答
反对 回复 2021-09-13
  • 2 回答
  • 0 关注
  • 263 浏览
慕课专栏
更多

添加回答

举报

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