Arrays 术语“;动态调整大小”;对于切片合理,当切片的最大长度小于基础数组的长度时?

Arrays 术语“;动态调整大小”;对于切片合理,当切片的最大长度小于基础数组的长度时?,arrays,go,slice,Arrays,Go,Slice,发件人: 数组具有固定大小。另一方面,切片是数组元素的动态大小的灵活视图 当切片不能超出基础数组的大小时,如何将其称为动态大小。即使有上限,动态大小仍然是动态的:它可以在零和上限之间变化 这就是说,如果您使用一个可以“增长”一个片的操作,它总是返回一个新片,或者获取一个指向片的指针(通常是前者),以便需要超过当前容量的例程可以分配一个新的、更大的数组1,并使片使用该数组而不是旧数组 这就是为什么append返回一个新值,并且您必须写入: s = append(s, element) 比如说 (

发件人:

数组具有固定大小。另一方面,切片是数组元素的动态大小的灵活视图


当切片不能超出基础数组的大小时,如何将其称为动态大小。即使有上限,动态大小仍然是动态的:它可以在零和上限之间变化

这就是说,如果您使用一个可以“增长”一个片的操作,它总是返回一个新片,或者获取一个指向片的指针(通常是前者),以便需要超过当前容量的例程可以分配一个新的、更大的数组1,并使片使用该数组而不是旧数组

这就是为什么
append
返回一个新值,并且您必须写入:

s = append(s, element)
比如说

(如果有上一个底层数组,则在适当的时候进行垃圾收集。nil片没有底层数组,因此容量为零。)


1运行时使用
unsafe
和其他特殊技巧分配此数组,绕过类型检查,但与运行时自己的垃圾收集代码协调。因此,它可以分配一个数组,该数组的大小是在运行时而不是在编译时选择的。编译器的
new
make
append
内置程序也可以使用此功能


您可以使用
safe
自己编写这种复杂的代码,但是如果您这样做,那么当新的Go版本发布时,如果新的Go在内部更改了某些内容,您就有可能不得不重写代码。因此,不要这样做:使用
append
make
使用已经为您设置的切片数据创建运行时大小的数组。

Go数组的大小在编译时是固定的。Go切片的大小在运行时动态设置


参考资料:

当切片不能超过底层数组的大小时,如何将其称为动态大小的切片

这些类型是静态和动态的。数组类型类似于
[4]byte
——大小是类型定义的一部分,因此在编译时设置。只有
[4]字节
可以存储在
[4]字节
类型的变量中。不是
[3]字节
,也不是
[5]字节
。它是静态的

切片类型类似于
[]字节
——大小不是类型定义的一部分,因此它不是在编译时设置的,任何大小的切片都可以在运行时存储在
[]字节
中。它可以是零长度,也可以是千长度,也可以是一个四字节的窗口,进入一个百万长度的数组。它是动态的


在运行时,片的大小也可以在其容量范围内收缩和增长,但容量只能通过替换基础阵列(作为一个阵列,其大小是固定的)来改变。例如,这是通过
追加
在后台自动完成的。但是,至少在我看来,这并不是让切片“动态”的原因;事实上,一个切片在运行时可以是任意大小的——在编译时它是未知的。这就是我将它们定义为“动态”的原因。

当一个片超出基础数组的容量时,将分配一个基础数组并复制内容。@Flimzy:仅适用于Go
append
buit in函数。@peterSO:是,但是,有没有其他方法可以扩展切片的容量?@Flimzy:标准库是一个很好的地方,可以看看它是如何完成的。查看
bytes.Buffer
func(b*Buffer)grow(n int)int方法的源代码:。grow增加缓冲区以保证n个字节的空间。这有点混乱。所以,一旦我们在运行时对一个切片执行了一些追加操作,那么底层数组如何动态地重新调整大小呢?如果动态重新调整大小发生在运行时,那么新的数组大小不是在运行时分配的吗?@sofs1:如果s的容量不够大,无法容纳附加值,append将分配一个新的、足够大的基础数组,该数组同时容纳现有的切片元素和附加值。否则,append将重新使用基础数组。这发生在运行时。“这发生在运行时”与“Go数组的大小在编译时是固定的”相矛盾。那么,我们可以假设第一次单独分配数组大小是在编译时发生的吗?@sofs1:Go数组类型的大小在编译时是固定的。Go切片类型的Go运行时内置的
make
append
函数具有特殊权限。它们可以在运行时动态地分配底层数组。@sofs1:我在答案中添加了两个有用的引用。