Golang中切片的用法与本质详解

2020-01-28 13:28:56于丽

前言

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大

Go的切片类型为处理同类型数据序列提供一个方便而高效的方式。 切片有些类似于其他语言中的数组,但是有一些不同寻常的特性。 本文将深入切片的本质,并讲解它的用法。

数组

Go的切片是在数组之上的抽象数据类型,因此在了解切片之前必须要先理解数组。

数组类型定义了长度和元素类型。例如, [4]int 类型表示一个四个整数的数组。 数组的长度是固定的,长度是数组类型的一部分(  [4]int 和  [5]int 是完全不同的类型)。 数组可以以常规的索引方式访问,表达式  s[n] 访问数组的第 n 个元素。


var a [4]int
a[0] = 1
i := a[0]
// i == 1

数组不需要显式的初始化;数组的零值是可以直接使用的,数组元素会自动初始化为其对应类型的零值:


// a[2] == 0, int 类型的零值

类型 [4]int 对应内存中四个连续的整数:


Go的数组是值语义。一个数组变量表示整个数组,它不是指向第一个元素的指针(不像 C 语言的数组)。 当一个数组变量被赋值或者被传递的时候,实际上会复制整个数组。 (为了避免复制数组,你可以传递一个指向数组的指针,但是数组指针并不是数组。) 可以将数组看作一个特殊的struct,结构的字段名对应数组的索引,同时成员的数目固定。

数组的字面值像这样:


b := [2]string{"Penn", "Teller"}

当然,也可以让编译器统计数组字面值中元素的数目:


b := [...]string{"Penn", "Teller"}

这两种写法, b 都是对应  [2]string 类型。

切片

数组虽然有适用它们的地方,但是数组不够灵活,因此在Go代码中数组使用的并不多。 但是,切片则使用得相当广泛。切片基于数组构建,但是提供更强的功能和便利。

切片类型的写法是 []T ,  T 是切片元素的类型。和数组不同的是,切片类型并没有给定固定的长度。

切片的字面值和数组字面值很像,不过切片没有指定元素个数:


letters := []string{"a", "b", "c", "d"}

切片可以使用内置函数 make 创建,函数签名为:


func make([]T, len, cap) []T

其中T代表被创建的切片元素的类型。函数 make 接受一个类型、一个长度和一个可选的容量参数。 调用  make 时,内部会分配一个数组,然后返回数组对应的切片。