本文的翻译是专门为Golang Developer课程的学生准备的, 该课程从今天开始!
刚开始时,很容易将数组和切片视为相同,但是名称不同:两者都是表示集合的数据结构。 但是,实际上它们彼此非常不同。
在本文中,我们将研究它们在Go中的区别和实现。
我们将转向示例,以便您可以更明智地决定将其应用于何处。
数组
数组是固定大小的集合。 这里的重点放在固定大小上,因为一旦您设置了数组的长度,以后您将无法更改它。
让我们来看一个例子。 我们将创建一个包含四个整数值的数组:
arr := [4]int{3, 2, 5, 4}
长度和类型
在上面的示例中,变量
arr
定义为类型
[4]int
的数组,这意味着该数组由四个元素组成。 重要的是要注意,类型定义中包括了大小
4
。
因此,实际上,不同长度的数组是不同类型的数组。 在这种情况下,不能将不同长度的数组彼此等同,也不能将一个数组的值分配给另一个数组:
longerArr := [5]int{5, 7, 1, 2, 0} longerArr = arr
我发现数组在结构方面很容易谈论。 如果尝试创建类似于数组的
结构 ,则很可能会得到以下信息:
实际上,不建议这样做,但这是了解为什么不同长度的数组是不同类型的数组的好方法。
内存表示
该数组存储为特定类型的
n
个块的序列:

初始化数组变量时将分配此内存。
通过链接传递
Go没有通过引用传递的东西;相反,所有东西都是通过值传递的。 如果将数组的值分配给另一个变量,则将简单地复制分配的值。

如果仅要将“引用”传递给数组,请使用指针:

在分配内存和函数时,数组实际上是一种简单的数据类型,其工作方式与结构非常相似。
切片
切片可以视为数组的扩展实现。
Go中实现了切片,以覆盖开发人员在使用集合时遇到的一些非常常见的用例,例如动态调整集合的大小。
slice声明与数组声明非常相似,只是省略了长度说明符:
slice := []int{4, 5, 3}
如果仅看代码,似乎切片和数组非常相似,但是它们的主要区别在于实现和使用条件。
内存表示
切片的分配方式与数组不同,本质上是修改后的指针。 每个切片包含三个信息块:
- 指向数据序列的指针。
- 长度,该长度确定切片中当前包含的元素数。
- 容量(capacity),它确定提供的存储单元的总数。

因此,可以将不同长度的切片彼此分配。 它们是同一类型,并且指针,长度和音量可以变化:
slice1 := []int{6, 1, 2} slice2 := []int{9, 3}
切片与数组不同,在初始化期间不会分配内存。 实际上,切片使用
nil
值初始化。
通过链接传递
当您将切片分配给另一个变量时,您仍在传递值。 在此,该值仅指指针,长度和体积,而不指元素本身占用的内存。

新增项目
要将新元素添加到切片,必须使用
append
函数。
nums := []int{8, 0} nums = append(nums, 8)
在幕后,看起来就像为新元素分配一个指定的值,然后–返回新的slice。 新切片的长度将增加一倍。

如果在添加元素时长度增加了一个,从而超过了声明的体积,则有必要提供一个新体积(在这种情况下,当前体积通常会加倍)。
这就是为什么通常建议使用预先指定的长度和体积创建切片的原因(尤其是如果您清楚地知道所需的切片大小):
arr := make([]int, 0, 5)
使用什么:数组或切片?
数组和切片是完全不同的东西,因此它们的用例也有所不同。
让我们看一些开源示例和Go标准库,以了解使用什么以及何时使用。
情况1:UUID
UUID是128位数据,通常用于标记对象或实体。 通常,它们以十六进制值表示,并用破折号分隔:
e39bdaf4-710d-42ea-a29b-58c368b0c53c
在
Google UUID库中,UUID表示为16个字节的数组:
type UUID [16]byte
这是有道理的,因为我们知道UUID由128位(16个字节)组成。 我们不会在UUID中添加或删除任何字节,因此将使用数组来表示它。
情况2:对整数值进行排序
在此示例中,我们将使用
sort标准库中的
sort.Ints
函数:
s := []int{5, 2, 6, 3, 1, 4}
sort.Ints
函数采用一片整数,然后按值的升序对其进行排序。 切片最好在这里使用,原因有两个:
- 未指定整数数(排序的整数数可以是任意数);
- 数字需要按升序排序。 使用数组将确保将整数的整个集合作为值传递,因此该函数将对自己的副本进行排序,而不是传递给它的集合。
结论
现在,我们已经研究了数组和切片之间的关键区别以及它们的用例,我想提供一些提示,使您可以更轻松地决定使用哪种设计:
- 如果一个实体由一组固定长度的非空元素描述,则使用数组。
- 描述要添加或从中删除项目的集合时,请使用切片。
- 如果集合可以包含任意数量的元素,请使用切片。
- 您会以任何方式更改收藏吗? 如果是这样,则应使用切片。
如您所见,切片涵盖了构建Go应用程序的大多数情况。 但是,数组有生存的权利,而且,它们非常有用,尤其是在出现合适的用例时。