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

Ton*_*yGW 1 append go capacity slice

制作一个Go中的容量参数slice对我来说没有多大意义.例如,

aSlice := make([]int, 2, 2) //a new slice with length and cap both set to 2
aSlice = append(aSlice, 1, 2, 3, 4, 5) //append integers 1 through 5
fmt.Println("aSlice is: ", aSlice)  //output [0, 0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

如果切片允许插入比容量允许的更多元素,为什么我们需要在make()函数中设置它?

icz*_*cza 11

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

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

附加内置函数将元素附加到切片的末尾.如果它具有足够的容量,则会复制目标以容纳新元素.如果没有,将分配新的底层数组.Append返回更新的切片.因此有必要存储append的结果,通常在保存切片本身的变量中:

在制作切片时,make如果长度和容量相同,则可以省略容量,在这种情况下,它默认为指定的长度:

// These 2 declarations are equivalent:
s := make([]int, 2, 2)
s := make([]int, 2)
Run Code Online (Sandbox Code Playgroud)

另请注意,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))
Run Code Online (Sandbox Code Playgroud)

输出:

[0 0] 2 2
[0 0 1] 3 4
Run Code Online (Sandbox Code Playgroud)

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

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))
Run Code Online (Sandbox Code Playgroud)

输出:

[] 0 10
[1] 1 10
Run Code Online (Sandbox Code Playgroud)

如果您想更详细地了解切片,我推荐以下博客文章:

去切片:用法和内部

数组,切片(和字符串):'追加'的机制