Go 语言函数式编程系列教程(九) —— 数据类型篇:数组切片的创建和遍历

栏目: Go · 发布时间: 5年前

内容简介:在前一篇教程里我们已经介绍过数组的一个特点:数组的长度在定义之后无法修改,数组长度是数组类型本身的一部分,是数组的一个内置常量,因此我们无法在数组上做动态的元素增删操作。显然这种数据结构无法完全满足开发者的日常开发需求,尤其是从 PHP 转过来的开发人员(PHP 的数组非常灵活和强大),为此,Go 语言提供了数组切片(slice)来弥补数组的不足,数组切片一个最强大的功能就是支持对元素做动态增删操作,在介绍动态增删元素之前,我们先来了解下数组切片的定义和创建。在 Go 语言中,数组切片是一个新的数据类型,与

在前一篇教程里我们已经介绍过数组的一个特点:数组的长度在定义之后无法修改,数组长度是数组类型本身的一部分,是数组的一个内置常量,因此我们无法在数组上做动态的元素增删操作。显然这种数据结构无法完全满足开发者的日常开发需求,尤其是从 PHP 转过来的开发人员(PHP 的数组非常灵活和强大),为此,Go 语言提供了数组切片(slice)来弥补数组的不足,数组切片一个最强大的功能就是支持对元素做动态增删操作,在介绍动态增删元素之前,我们先来了解下数组切片的定义和创建。

数组切片的定义

Go 语言中,数组切片是一个新的数据类型,与数组最大的不同在于,切片的类型字面量中只有元素的类型,没有长度:

var slice []string = []string{"a", "b", "c"}

Go 语言函数式编程系列教程(九) —— 数据类型篇:数组切片的创建和遍历

因此它是一个可变长度的、同一类型元素集合,切片的长度可以随着元素数量的增长而增长(不会随着元素数量的减少而减少),不过数组切片从底层管理上来看依然使用数组来管理元素,可以看作是对数组做了一层简单的封装。基于数组,数组切片添加了一系列管理功能,可以随时动态扩充存储空间,下面我们就来看看数组切片的创建和使用。

创建数组切片

创建数组切片的方法主要有三种 —— 基于数组、数组切片和直接创建,下面我们来简要介绍一下这几种方法。

基于数组

数组切片可以基于一个已存在的数组创建。从这个层面来说,数组可以看作是切片的底层数组,而切片则可以看作是数组某个连续片段的引用。数组切片可以只使用数组的一部分元素或者整个数组来创建,甚至可以创建一个比所基于的数组还要大的数组切片:

// 先定义一个数组
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个元素),和数组一样,我们可以通过内置函数 lencap 来分别获取数组切片的长度和容量:

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) 
}

两种方式打印结果完全一致。

下一篇我们将给大家介绍数组切片的一些高级使用,比如动态增减元素、内容复制等。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

海星模式

海星模式

奥瑞·布莱福曼、罗德·贝克斯特朗 / 李江波 / 中信出版社 / 2008-1 / 36.00元

如果砍掉一只蜘蛛的脑袋,毫无疑问它会死掉;但是砍掉海星的一条手臂,它却会长出一只新的来,就连那只砍掉的手臂也会长成一个完整的新海星。传统意义上自上而下的组织模式就像蜘蛛,然而现在正在改变着企业和世界面貌的却是海星型组织。 维基百科、craigslist和Skype的成功下面隐藏着什么样的力量?易趣公司和通用电气公司与废奴和女权运动又有什么共同之处?到底是什么样的重大选择使得通用汽车公司与丰田......一起来看看 《海星模式》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具