数据类型篇(七):数组切片的创建和遍历
在前一篇教程里我们已经介绍过数组的一个特点:数组的长度在定义之后无法修改,数组长度是数组类型本身的一部分,是数组的一个内置常量,因此我们无法在数组上做动态的元素增删操作。显然这种数据结构无法完全满足开发者的日常开发需求,尤其是从 PHP 转过来的开发人员(PHP 的数组非常灵活和强大),为此,Go 语言提供了数组切片(slice)来弥补数组的不足,数组切片一个最强大的功能就是支持对元素做动态增删操作,在介绍动态增删元素之前,我们先来了解下数组切片的定义和创建。
数组切片的定义
在 Go 语言中,数组切片是一个新的数据类型,与数组最大的不同在于,切片的类型字面量中只有元素的类型,没有长度:
var slice []string = []string{"a", "b", "c"}
因此它是一个可变长度的、同一类型元素集合,切片的长度可以随着元素数量的增长而增长(不会随着元素数量的减少而减少),不过数组切片从底层管理上来看依然使用数组来管理元素,可以看作是对数组做了一层简单的封装。基于数组,数组切片添加了一系列管理功能,可以随时动态扩充存储空间,下面我们就来看看数组切片的创建和使用。
创建数组切片
创建数组切片的方法主要有三种 —— 基于数组、数组切片和直接创建,下面我们来简要介绍一下这几种方法。
基于数组
数组切片可以基于一个已存在的数组创建。从这个层面来说,数组可以看作是切片的底层数组,而切片则可以看作是数组某个连续片段的引用。数组切片可以只使用数组的一部分元素或者整个数组来创建,甚至可以创建一个比所基于的数组还要大的数组切片:
// 先定义一个数组
months := [...]string{"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"}
// 基于数组创建数组切片
q2 := months[3:6] // 第二季度
summer := months[5:8] // 夏季
fmt.Println(q2)
fmt.Println(summer)
运行结果为:
[April May June]
[June July August]
Go 语言支持通过 array[first:last]
这样的方式来基于数组生成一个数组切片,而且这个用法还很灵活,比如下面几种用法都是合法的:
基于 months
的所有元素创建数组切片(全年):
all := months[:]
基于 months
的前 6 个元素创建数组切片(上半年):
firsthalf := months[:6]
基于从第 6 个元素开始的所有元素创建数组切片(下半年):
secondhalf := months[6:]
另外,通过这个示例,还可以探讨下数组切片底层的结构,数组切片底层引用了一个数组,由三个部分构成:指针、长度和容量,指针指向数组起始下标,长度对应切片中元素的个数,容量则是切片起始位置到底层数组结尾的位置,切片长度不能超过容量,比如上面的数组切片 q2
,其指针指向底层数组 months
下标为 3
的位置,切片长度是3,切片容量是9(从下标3开始到下标11结束,可容纳9个元素),和数组一样,我们可以通过内置函数 len
和 cap
来分别获取数组切片的长度和容量:
fmt.Println(len(q2)) // 3
fmt.Println(cap(q2)) // 9
基于数组切片
类似于数组切片可以基于一个数组创建,数组切片也可以基于另一个数组切片创建:
firsthalf := months[:6]
q1 := firsthalf[:3] // 基于firsthalf的前3个元素构建新数组切片
基于 firsthalf
创建数组切片时,选择的 firsthalf
元素范围可以超过所包含的元素个数,比如 q1
可以基于firsthalf
的前 9 个元素创建:
q1 := firsthalf[:9]
打印结果是:[January February March April May June July August September]
。
因为 firsthalf
的容量是 12,只要选择的范围不超过 firsthalf
的容量,那么这个创建操作就是合法的。
直接创建
并非一定要事先准备一个数组才能创建数组切片,Go 语言提供的内置函数 make()
可以用于灵活地创建数组切片。下面的例子示范了直接创建数组切片的各种方法:
// 创建一个初始元素个数为 5 的数组切片,元素类型为整型,初始值为 0,容量为 5
mySlice1 := make([]int, 5)
创建一个初始元素个数为 5 的整型数组切片,初始值为 [0 0 0 0 0]
,并预留 10 个元素的存储空间(容量为10):
mySlice2 := make([]int, 5, 10)
此外,还可以直接创建并初始化包含 5 个元素的数组切片:
mySlice3 := []int{1, 2, 3, 4, 5}
事实上,使用直接创建的方式来创建数组切片 Go 底层还是会有一个匿名数组被创建出来,然后调用基于数组创建切片的方式返回数组切片,只是上层不需要关心这个匿名数组的操作而已。
遍历数组切片
操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用 len()
函数获取元素个数,并支持使用 range
关键字来快速遍历所有元素。
传统的元素遍历方法如下:
for i := 0; i < len(summer); i++ {
fmt.Println("summer[", i, "] =", summer[i])
}
打印结果如下:
summer[ 0 ] = June
summer[ 1 ] = July
summer[ 2 ] = August
使用 range
关键字可以让遍历代码显得更简洁,range
表达式有两个返回值,第一个是索引,第二个是元素的值:
for i, v := range summer {
fmt.Println("summer[", i, "] =", v)
}
两种方式打印结果完全一致。
下一篇我们将给大家介绍数组切片的一些高级使用,比如动态增减元素、内容复制等。
5 Comments
数组切片下面的那张图使用什么工具能构建呢?@学院君
这种看起来像是ipad手绘的 我的图是从网上找的
打卡完成
通过数组或者数组切片创建切片时候,切片的长度是由截取的开始到最后,比如a:=b[3,4],长度为3到b最后一个元素的长度,不是3到4的长度
你说的那是容量 自己打印下
len(a)
看看