这是一个非常简单的问题:
如果可以超出Golang中某个切片的容量,为什么首先要有一个容量参数?
我认为这与内存管理有关,即某种“知道在内存中分配切片的位置”,但我不完全知道。
答案 0 :(得分:9)
如果可以超出Golang中某个切片的容量,为什么首先要有一个容量参数?
我不知道您的意思是什么,但是容量不能超过。可以在不超过容量的长度(不包括其长度)的范围内对切片进行索引,并且可以对其容量(包括在内)的容量进行重新切片。
a[x]
形式的主表达式如果
a
不是地图:...如果x
,则索引0 <= x < len(a)
在范围内 否则是不在范围内
...主要表达式:
a[low : high]
对于数组或字符串,如果
0 <= low <= high <= len(a)
,则索引在范围内,否则,它们在范围之外。对于切片,索引的上限是切片容量cap(a)
而不是长度。
还有:
...主要表达式:
a[low : high : max]
如果
0 <= low <= high <= max <= cap(a)
,则索引在范围内;否则,它们超出范围。
您可以为内置make()
提供容量,以考虑未来的增长,因此,如果您需要向其追加元素或需要对其进行切片,则将需要较少的分配。内置的append()
仅在切片具有足够的额外元素容量时才对其切片,但是如果它没有空间容纳新切片,则必须分配新的后备数组(并将现有内容复制到其中)元素。 append()
将返回可能指向也可能不指向原始后备数组的新切片。
让我们看一个例子。让我们创建一个长度和容量为0的切片,并向其添加10个元素。为了查看何时发生新的重新分配,我们还打印了其第一个元素(第0个元素)的地址:
fmt.Println("With 0 capacity")
s := make([]int, 0)
for i := 0; i < 10; i++ {
s = append(s, i)
fmt.Println(i, &s[0])
}
这将输出:
With 0 capacity
0 0x416030
1 0x416030
2 0x416040
3 0x416040
4 0x452000
5 0x452000
6 0x452000
7 0x452000
8 0x434080
9 0x434080
如您所见,当我们附加第三个(i=2
),第五个(i=4
)和第九个元素(i=8
时,以及当我们附加第三个元素时,都会分配一个新的支持数组追加了第一个元素(因为原始后备数组无法容纳任何元素)。
现在,当我们创建长度为0但容量为10的初始切片时,让我们重复上面的示例:
fmt.Println("With 10 capacity")
s = make([]int, 0, 10)
for i := 0; i < 10; i++ {
s = append(s, i)
fmt.Println(i, &s[0])
}
现在的输出将是:
With 10 capacity
0 0x44c030
1 0x44c030
2 0x44c030
3 0x44c030
4 0x44c030
5 0x44c030
6 0x44c030
7 0x44c030
8 0x44c030
9 0x44c030
如您所见,第一个元素的地址从未改变,这意味着在后台没有新的后备数组分配发生。
在Go Playground上尝试该示例。
答案 1 :(得分:2)
要增加切片的容量,必须创建一个更大的新切片并将原始切片的内容复制到其中。
如果可以超出Golang中一个切片的容量,为什么会有 容量参数排在首位?
假设我们提前知道了slice的容量,那么我们可以使用make内置函数的Capacity参数来分配内存,而不是使用append来动态增加slice的容量,而这并不高效。
所以在下面的示例中
type Element struct {
Number int
}
func main() {
Max := 100000
startTime := time.Now()
// Capacity given
elements1 := make([]Element, Max, Max)
for i := 0; i < Max; i++ {
elements1[i].Number = i
}
elapsedTime := time.Since(startTime)
fmt.Println("Total Time Taken with Capacity in first place: ", elapsedTime)
startTime = time.Now()
// Capacity not given
elements2 := make([]Element, 0)
for i := 0; i < Max; i++ {
elements2 = append(elements2, Element{Number: i})
}
elapsedTime = time.Since(startTime)
fmt.Println("Total Time Taken without capacity: ", elapsedTime)
}
output
Total Time Taken with Capacity in first place: 121.084µs
Total Time Taken without capacity: 2.720059ms
首先构建具有容量的切片所需的时间少于动态构建所需的时间
所以要回答您的问题,首先要考虑容量参数以提高性能和内存效率
答案 2 :(得分:1)
golang博客中有许多出色的文章。 one on slices,将为您提供切片的基础实现以及容量如何工作的详细见解。
该帖子介绍了append
操作的工作方式以及容量值如何使append
知道是重用基础内存阵列,还是在需要更多容量时分配更大的阵列。