数组和切片的区别

  • 数组的零值是元素类型的零值,切片的零值是 nil;
  • 数组是固定长度,切片是可变长度;
  • 数组是值类型,切片是引用类型。

数组

Ø 数组的概念

数组是相同类型的一组数据构成的长度固定的序列,其中数据类型包含了基本数据类型、复合数据类型和自定义类型。数组中的每一项被称为数组的元素。数组名是数组的唯一标识符, 数组的每一个元素都是没有名字的,只能通过索引下标(位置)进行访问。因为数组的内存是一段连续的存储区域,所以数组的检索速度是非常快的,但是数组也有一定的缺陷,就是定义后长度不能更改。

Ø 数组的语法

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下。

以上为一维数组的定义方式,数组长度必须是整数且大于 0,未初始化的数组不是nil,也就是说没有空数组(与切片不同)。

初始化数组语法格式如下。

初始化数组中 {} 中的元素个数不能大于 [] 中的数字。

如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小。可以忽略声明中数组的长度并将其替换为…。编译器会自动计算长度。语法格式如下。

以上两种初始化方式相同,虽然第二种没有设置数组的大小。

修改数组内容,语法格式如下。

以上实例读取数组第5个元素。数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为 0,第二个索引为 1,以此类推。

Ø 数组的长度

数组的长度是该数组类型的一个内置常量,通过将数组作为参数传递给len()函数,可以获得数组的长度。忽略声明中数组的长度并将其替换为“…”,编译器可以找到长度。接下来使用案例演示获取数组长度的使用方式,具体如例所示。

Ø 遍历数组

在数组中查找目标元素,需要进行遍历,在Go语言中数组的遍历方式。

Ø 多维数组

由于数据的复杂程度不一样,数组可能有多个下标。一般将数组元素下标的个数称为维数,根据维数,可将数组分为一维数组、二维数组、三维数组、四维数组等。二维及以上的数组可称为多维数组。

Go 语言的多维数组声明方式:

1. 二维数组

在实际的工作中,仅仅使用一维数组是远远不够的,例如,一个学习小组有10个人,每个人有三门课的考试成绩,如果使用一维数组解决是很麻烦的。这时,可以使用二维数组。

二维数组是最简单的多维数组,二维数组的本质也是一个一维数组,只是数组成员,由基本数据类型变成了构造数据类型(一维数组)。

二维数组的定义方式如下。

二维数组初始化,语法格式如下。

在上述定义的二维数组中,共包含3*4个元素,即12个元素。接下来,通过一张图来描述二维数组a的元素分布情况,如图所示。

二维数组通过指定坐标来访问。如数组中的行索引与列索引。语法格式如下。

以上实例访问了二维数组 val 第三行的第四个元素。

二维数组可以使用循环嵌套来输出元素,具体语法通过案例演示。

2. 三维数组

三维数组的本质也是一个一维数组,只是数组成员由基本数据类型变成了构造数据类型(二维数组)。如同阅兵仪式的多个方阵。

定义三维数组的语法格式如下。

多维数组在实际的工作中极少使用,并且使用方法与二维数组相似,本书不再做详细的讲解,有兴趣的读者可以自己学习。

Ø 数组是值类型

Go语言中的数组并非引用类型,而是值类型。当它们被分配给一个新变量时,会将原始数组复制出一份分配给新变量。因此对新变量进行更改,原始数组中不会有反映。

当将数组传递给函数作为参数时,它们将通过值传递,原始数组依然保持不变。

切片



Ø 切片的概念

Go 语言中数组的长度不可改变,但在很多应用场景中,在初始定义数组时,数组的长度并不可预知,这样的序列集合无法满足要求,Go中提供了另外一种内置类型“切片(slice)”,弥补了数组的缺陷。切片是可变长度的序列,序列中每个元素都是相同的类型。切片的语法和数组很像。

从底层来看,切片引用了数组的对象。切片可以追加元素,在追加时可能使切片的容量增大。与数组相比,切片不需要设定长度,在[]中不用设定值,相对来说比较自由。

切片的数据结构可理解为一个结构体,这个结构体包含了三个元素:

l 指针,指向数组中切片指定的开始位置。

l 长度,即切片的长度。

l 容量,也就是切片开始位置到数组的最后位置的长度。

Ø 切片的语法

1. 声明切片

声明一个未指定长度的数组来定义切片,具体示例如下。

切片不需要说明长度。采用该声明方式且未初始化的切片为空切片。该切片默认为 nil,长度为 0。

使用make()函数来创建切片,语法格式如下。

使用make()函数来创建切片可以简写为如下格式。

创建切片时可以指定容量,其中capacity为可选参数:make([]T, length, capacity)。详情参见。

2. 初始化

(1)直接初始化切片,语法格式如下。

(2)通过数组截取来初始化切片,语法格式如下。

切片中包含数组所有元素,语法格式如下。

将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片(前闭后开),长度为endIndex-startIndex。

缺省endIndex时将表示一直到arr的最后一个元素,语法格式如下。

缺省startIndex时将表示从arr的第一个元素开始,语法格式如下。

(3)通过切片截取来初始化切片。

可以通过设置下限及上限来设置截取切片:[lower-bound:upper-bound],下面通过一个示例演示。

Ø len()和cap()函数

切片的长度是切片中元素的数量。切片的容量是从创建切片的索引开始的底层数组中元素的数量。切片可以通过 len()方法获取长度, 可以通过cap()方法获取容量。数组计算cap()结果与len()相同,具体使用细节。

Ø 切片是引用类型

切片没有自己的任何数据。它只是底层数组的一个引用。对切片所做的任何修改都将反映在底层数组中。数组是值类型,而切片是引用类型,两者区别。

修改切片数值,当多个片共享相同的底层数组时,对每个元素所做的更改将在数组中反映出来。

Ø append()和copy()函数

函数append()用于往切片中追加新元素,可以向切片里面追加一个或者多个元素,也可以追加一个切片。append()会改变切片所引用的数组的内容,从而影响到引用同一数组的其他切片。 当使用append()追加元素到切片时,如果容量不够(也就是(cap-len) == 0),Go就会创建一个新的内存地址来储存元素。

函数copy()会复制切片元素,将源切片中的元素复制到目标切片中,返回复制的元素的个数。copy()方法是不会建立源切片与目标切片之间的联系。也就是两个切片不存在联系,其中一个修改不影响另一个。

以上两个方法不适应于数组。

利用切片截取及append()函数实现切片删除元素。

删除第一个元素,具体方法如下所示。

删除最后一个元素,具体方法如下所示。

删除中间元素,具体方法如下所示。