Fork me on GitHub

Go语言开发-集合类型-数组和切片

4.2.数组和切片

Go语言的数组是一个定长的具有相同类型元素的序列,可以通过使用本身就是数组的元素来创建多维数组。

数组的元素使用[]索引操作符来索引,索引从0开始,所以数组的第一个元素是array[0],最后一个元素是array[len(array)-1]。数组是可变的,所以我们可以使用array[index]语法以给定的索引位置来设置其元素。我们也可以在一个赋值表达式或函数调用中使用该语法来访问其元素。

可以使用下面的语法来创建数组︰

如果使用了…(省略号)操作符,Go语言会为我们计算数组的长度。(省略号操作符也可以用于其他目的,稍后我们会介绍)在任何情况下,数组的长度都是固定的且不可修改。

下面是一些例子,演示了如何创建和索引数组。

就像buffer、gridl和grid2变量那样,当创建数组时,如果它们没有被显示地初始化或只被部分初始化,Go语言会保证数组中的所有元素都被初始化成其零值。

我们可以使用len()函数得到数组的长度。因为数组的长度是固定的,所以它们的容量总是等于其长度,对于数组来说,cap()函数和len()函数都返回相同的的数字。数组与字符串和切片一样,都可以使用切片语法进行切片,只是其结果是一个切片而不是数组。另外,数组也可以使用for … range循环来进行遍历。

一般情况下,Go语言的切片比数组更加灵活、强大且方便。

数组是按值传递的,但是其传递成本可以通过使用指针来避免,而传递切片的成本比较低廉,而不必关心其长度和容量,因为它们是引用。(在64位机器上传递16字节,在32位机器上传递12字节,无论切片包含了多少元素。)数组的长度是固定的,而切片可以调整长度。Go语言标准库中所有函数的公有API使用的都是切片而不是数组。我们建议始终使用切片,除非在特殊情况下有非常特别的需求要用数组。数组和切片都可以使用表4.1中所示的语法来进行切片。

Go语言中的切片是可变长度的固定容量的具有相同类型元素的序列。尽管容量固定,但是可以通过将其切片来减少元素,也可以使用内置append()函数来添加元素,我们将在本节后面介绍这些特性。多维切片可以通过使用本身就是切片的元素来创建,而其内部切片的长度也是可以变化的。

虽然数组和切片保存的是相同类型的元素,但是在实际使用中并无此限制,这是因为其类型可以是一个接口。所以我们可以保存满足指定接口的任意类型的元素(即,具有自己的方法或接口所需的方法)。我们甚至可以让数组或切片为空接口interface{},这意味着我们可以保存任意类型的任意元素,但是这会导致我们访问其中的元素时需要使用类型断言或类型开关。(接口将在第6章介绍;反射将在第9章介绍)。可以使用下面的语法创建切片:

内置的make()函数用于创建切片、映射和管道。当用于创建一个切片时,它创建的是一个隐藏的以零值初始化的数组,并返回指向该隐藏数组的切片引用。与Go语言中的所有数组一样,该隐藏数组也是固定长度的,如果使用了第一种语法,则数组的长度与切片的容量一致,如果使用第二种语法,则数组的长度等于切片的长度,如果使用复合(第三种或第四种)语法,则数组的长度为大括号中元素的数量。

一个切片的容量是其隐藏数组的长度,且其长度不能超过其容量。在第一种语法中,切片的长度必须小于等于其容量,在当我们希望其初始长度小于其容量时,通常使用此语法。当希望其长度和容量一致时,我们可以使用第二、第三和第四种语法。复合(第四种)语法是非常方便的,因为它允许我们用一些初始值来创建切片。

[]Type{}语法等同于make([]Type,0)语法;它们创建的都是空切片。但是这并不是无用的,因为我们可以使用内置的append()函数来高效地增加切片的容量。然而,在实际使用中,最好使用make()来创建一个初始值为空的切片,只要给给make()指定一个大小为0的长度和一个大小不为0的容量,也就是,我们希望切片保存的元素的个数。

表4.1 切片操作

s[n] 切片s中索引位置为n的元素
s[n:m] 切片s中截取从索引位置n到m-1处的切片
s[n:] 切片s中截取从索引位置n到结尾处的切片
s[:m] 切片s中截取从索引位置0到m-1处的切片
s[:] 切片s中截取从索引位置0到结尾处的切片
cap(s) 切片s的容量;总是大于等于len(s)
len(s) 切片s中元素的个数;总是小于等于cap(s)
s = s[:cap(s)] 如果切片的长度和容量不同,则将其长度增大到其容量

切片的有效索引范围为从0到len(slice)-1。切片可以被再次切片来减小其长度,如果切片的容量大于其长度,则可以通过将其再次切片来将其长度增加到其容量值。我们也可以使用内置的append()函数来增加一个切片的容量;本节稍后将会介绍几个使用该函数的例子。

图 4.3 给出了切片与其隐藏数组之间的关系。下面这些是它给出的切片。

因为切片s、t和u都指向同一个底层数组,所以修改其中一个会影响到其它所有指向该

数组的引用。

1234567890

图4.3 切片与其底层数组剖析

使用内置的make()函数或复合语法是创建切片的最好方式,但是这里我们给出了一种在实际中不会用到但是能够明显展示出数组切片关系的方法。第一条语句使用内置的new()函数创建了一个指向数组的指针,然后取得整个数组的切片,这将产生一个长度和容量都等于数组长度的切片,但是每一个元素都会被设置为其零值,在本例中是被设置为一个空字符串。第二个语句通过为每个元素设置其初始值来完成切片的设置,这样创建的切片就和我们之前使用复合语法创建的切片完全一样。

下面基于切片的例子与我们之前介绍的关于数组的例子功能一样,只是我们将buffer的容量设置为大于其长度来演示它是如何做到的。

buffer中的数据是前len(buffer)个元素;其它元素是不可访问的,除非我们将buffer再次切片,稍后我们将介绍如何做到这一点。

我们创建了一个初始长度为3(即,可以含有3个切片)且容量为3(如果没有特别指定,容量默认等于其长度)的切片的切片grid1,接下来我们将grid1最外层的每一个切片赋值为包含3个元素的切片。当然,我们也可以将最内层切片设置为具有不同的长度。

对于grid2,我们必须为其指定每个值,因为我们是使用复合语法创建的且Go语言没有其它途径知道我们需要多少个元素。最后,我们创建了一个具有不同长度切片的切片,例如,grid2:=[][]int{{9,7},{8},{4, 2, 6}},这将使得grid2切片的长度为3且其所包含的切片的长度分别是2、1和3。


目录


作者:Johnson
原创文章,版权所有,转载请保留原文链接。

发表评论

电子邮件地址不会被公开。 必填项已用*标注