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

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

内容简介:在前一篇教程里我们已经介绍过数组的一个特点:数组的长度在定义之后无法修改,数组长度是数组类型本身的一部分,是数组的一个内置常量,因此我们无法在数组上做动态的元素增删操作。显然这种数据结构无法完全满足开发者的日常开发需求,尤其是从 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) 
}

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

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


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

查看所有标签

猜你喜欢:

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

Transcending CSS

Transcending CSS

Andy Clarke、Molly E. Holzschlag / New Riders / November 15, 2006 / $49.99

As the Web evolves to incorporate new standards and the latest browsers offer new possibilities for creative design, the art of creating Web sites is also changing. Few Web designers are experienced p......一起来看看 《Transcending CSS》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码