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

Go中的切片:为什么它允许追加超出容量允许的内容?,go,append,slice,capacity,Go,Append,Slice,Capacity,在Go中制作切片的容量参数对我来说没有多大意义。比如说, 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] 如果片允许插入的

在Go中制作切片的容量参数对我来说没有多大意义。比如说,

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]
如果片允许插入的元素多于容量允许的元素,为什么我们需要在make函数中设置它?

内置函数使用指定的片来附加元素,如果它有足够大的容量容纳指定的元素

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

append内置函数将元素追加到片段的末尾。如果目的地具有足够的容量,则会重新许可该目的地以容纳新元素。否则,将分配一个新的底层数组。Append返回更新的切片。因此,有必要将append的结果存储在保存切片本身的变量中:

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

// These 2 declarations are equivalent:
s := make([]int, 2, 2)
s := make([]int, 2)
还要注意,append在片段的最后一个元素之后追加元素。上面的切片在声明之后已经有了lens==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
[] 0 10
[1] 1 10
因此,在您的示例中,您应该这样做:

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 0] 2 2
[0 0 1] 3 4
[] 0 10
[1] 1 10
如果您想更详细地了解切片,我推荐以下博客文章:

如果内置函数有足够大的容量容纳指定的元素,则它将使用指定的片向其追加元素

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

append内置函数将元素追加到片段的末尾。如果目的地具有足够的容量,则会重新许可该目的地以容纳新元素。否则,将分配一个新的底层数组。Append返回更新的切片。因此,有必要将append的结果存储在保存切片本身的变量中:

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

// These 2 declarations are equivalent:
s := make([]int, 2, 2)
s := make([]int, 2)
还要注意,append在片段的最后一个元素之后追加元素。上面的切片在声明之后已经有了lens==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
[] 0 10
[1] 1 10
因此,在您的示例中,您应该这样做:

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 0] 2 2
[0 0 1] 3 4
[] 0 10
[1] 1 10
如果您想更详细地了解切片,我推荐以下博客文章:


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

当附加的容量超过容量时,运行时需要为新元素分配更多内存。这代价高昂,还可能导致内存碎片


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

这主要是一种优化,go并不是唯一的,其他语言中的类似结构也有这一点

当附加的容量超过容量时,运行时需要为新元素分配更多内存。这代价高昂,还可能导致内存碎片

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

注意,您不必将其设置为make。有一个make[]T,n来给你一段长度为n的T。注意,你不必在make中设置它。有一个make[]T,n,给你一片长度为n的T。