3.1 数组

与大多数编程语言一样,Go也有数组类型,但是在Go中很少直接使用数组。稍后会解释其原因,不过在此之前让我们先快速地了解如何定义和使用数组。

数组中的所有元素都必须指定类型(但并不意味着它们必须是相同的类型)。有几种定义数组的方式。在第一种形式中,需要像这样指定数组的长度和数组中元素的类型:

这会创建一个包含3个整型元素的数组。由于没有指定数组的值,因此所有的位置(x[0]x[1]x[2])都被初始化为整型的零值,即0。如果需要指定数组的初始值,可以使用数组字面量:

如果有一个稀疏数组(这个数组中大多数值都为零值),那么可以这样指定一部分值:

这会创建一个具有12个整型元素的数组:[1,0,0,0,0,4,6,0,0,0,100,15]。

在使用数组字面量初始化一个数组时,也可以不定义具体的长度而是使用...代替:

可以使用==!=来比较数组:

Go中只有一维数组,但是可以模拟多维数组:

这里定义的x是一个长度为2的数组,数组元素的类型是整型,长度为3。这听起来挺奇怪的,但是在其他语言中被称为“矩阵”,不过Go并不是一种具有真正矩阵支持的语言,仅使用二维数组模拟矩阵。

就像其他语言一样,在Go中读取和写入数组一般使用中括号语法:

读写操作不能超出数组的索引范围,也不能使用负数索引。如果使用常数和字面量索引,则会造成编译错误。而使用变量索引进行读写操作,超出索引范围后虽然可以编译通过,但是会在运行时引起panic(详见8.8节)。

最后,使用内置的len函数传入一个数组会返回该数组的长度:

之前提到过数组在Go中很少被显式地使用。这是因为它们有一个特殊的限制:Go认为数组的长度属于其类型的一部分。这就导致定义为[3]int的数组类型不同于定义为[4]int的数组类型,也意味着不能使用变量去指定数组的长度,因为类型必须在编译时而不是在运行时解析。

进一步而言,因为不同长度的数组可以认为是不同的类型,所以不同长度的数组不能互相转换,同样也不能编写一个函数来处理任意长度的数组,并且也不能给变量赋值长度不同的数组。

 我们会在第6章介绍内存布局时讨论数组的内部工作原理。

由于这些限制,除非已经知道需要的长度,否则不要使用数组。例如,标准库中的一些密码学相关函数会返回数组,因为它们的算法已经定义好了校验和的长度。这些只是特例,不是惯例。

为什么Go语言中存在这样的限制呢?Go中存在数组的主要原因是为切片提供后备存储,这是Go最有用的功能之一。