在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]
如果切片允许插入的元素多于容量允许的元素,为什么我们需要在make()函数中设置它?
答案 0 :(得分:11)
内置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
如果您想更详细地了解切片,我推荐以下博客文章:
答案 1 :(得分:3)
它主要是一种优化,并不是独一无二的,其他语言中的类似结构也是如此。
当您追加超过容量时,运行时需要为新元素分配更多内存。这很昂贵,也可能导致内存碎片化。
通过指定容量,运行时会预先分配所需的内容,并避免重新分配。但是,如果您事先不知道估计的容量或者它发生了变化,则无需进行设置,运行时会重新分配所需内容并增加容量本身。