Arrays AND Slices

概述

Array(数组)Slice(切片)

Array(数组)

参考:

Array(数组) 是具有相同的唯一类型的一组 已编号、且长度固定 的数据项序列。每个数据项称为 element(元素)、长度指的是元素的个数、编号指每个元素的 index(索引),索引号从 0 开始。

[n]T 用以表示一个数组,该数组包含 n 个 T 类型的值。

Array 的声明

var ArrayID [LENGTH]TYPE
  • ArrayID # 标识符(i.e.数组的名字)
  • LENGTH # 数组长度(i.e.元素的个数)
  • TYPE # 每个元素的数据的类型。
  • **[ ]** # 括号是数组类型的标识符,不要忘记写。

比如:var arr [10]int这定义了一个名为 arr 的数组,这个数组由 10 个 int 类型的数据组成。简化点的口头语,声明了一个长度为 10 的整形数组。

Array 的赋值

arr[0] = "Hello" 为数组的 0 号元素赋值。

Array 的实例化

数组声明后,默认初始化每个元素的值为 0,后续可以对每个元素进行赋值。数组可以有两种初始化方式

  • 每次对一个元素进行赋值,一般使用循环来实现
  • 使用{}大括号,直接对数组进行初始化
    • e.g.var arr = [5]int{1,5,23,2,10}

Array 的引用

引用数组的长度

len(MapID)

使用 len() 函数,括号内为数组标识符。数组的长度也就是元素的数目,必须是固定的并且在声明该数组时就给出,数组长度最大为 2Gb。格式为 len(ARRAYS) len 是 length 的缩写,ARRAYS 是数组变量的名称。

  • e.g.对于上面例子中定义的数组,数组的长度为len(arr)

引用数组中的元素

ArrayID[INDEX]
  • ArrayID # 数组标识符
  • INDEX # 元素编号

数组的元素可以通过索引(数组的位置,索引有时候也叫作数组中元素的编号)来读取(或修改),索引从 0 开始,第一个元素的索引为 0,第二个索引为 1,以此类推(长度为 3 的数组,元素的索引为 0、1、2)。

  • e.g.对于上面例子中定义的数组,第一个元素是arr[0],第二个元素是arr[1]…..第五个元素是arr[4]

多维数组

数组通常是一维的,但是可以用来组装成多维数组。e.g.[3][5]int有行有列,[2][2][2]float64立体效果。代码示例:multidim_array.go

Slice(切片)

Slice(切片) 是一个长度可变的数组,是数组的一部分;是对数组一个连续片段的引用。这个片段可以是整个数组、或是由起始和终止索引标识中间的元素子集,注意:终止索引标识符的元素不包括在切片内。

切片的由来:Go 中的数组是一个值,数组变量表示整个数组,而不是指向数组第一个元素的指针。这就意味,将一个数组当作参数传递时,会完全拷贝数组中的内容(当数组非常大的时候,会非常占用资源,使用起来也不便利),这时候就可以是使用切片来作为参数进行传递。**可以把数组当成一个存储元素的地方,具有索引,有着固定的大小。而切片则是指向这个存储元素地方的指针。**所以 Golang 中一般使用切片来对数组进行引用和传递参数。

注意:绝对不要用指针指向切片。切片本身已经是一个引用类型,所以它本身就是一个指针!

Slice 的声明

var SliceID []TYPE。MapID 为该切片的名字,[]中括号内不指明长度

Slice 的实例化

var SliceID []TYPE = ARR[START:END]。切片通过数组 ARR 从 START 号索引到 END-1 号索引之间的元素构成自己(切分数组,START:END被称为 slice 表达式)。切片的长度为 END-START,切片的容量为从所引用的数组索引号START这个元素到这个数组最后一个元素的所有元素的个数

  • e.g.如果定义了一个数组 var arr1 [7]int
    • var slice1 []type = arr1[2:5]slice1[0]等于arr1[2]len(slice1)切片长度为 3,cap(slice1)切片容量为 5
    • var slice2 []type = arr1[:] 切片 slice2 等于完整的 arr1 数组。另一种表示方式:slice2 = &arr1
    • arr1[2:]arr1[2:len(arr1)] 相同,表示包含了数组的 2 号索引到最后最一个索引的所有元素。
    • arr1[:3]arr1[0:3] 相同,表示包含了从数组的 0 号索引到 2 号索引的所有元素(不包括 3 号索引的元素)。
    • s := [3]int{1,2,3}[:]s := []int{1,2,3} 相同,表示由数字 1、2、3 组成的切片
    • s2 := s[:]使用切片组成的切片,拥有相同的元素,但是仍然指向相同的相关数组
    • var x = []int{2,3,4,5,11} 创建了一个长度为 5 的数组且创建了一个相关切片。

使用make()函数来创建一个切片,同时创建好相关数组。

格式:var SliceID []TYPE = make([]TYPE, LEN, CAP)也可以简写为SliceD := make([]TYPE, LEN, CAP)(其中 CAP 是可省的,默认与 LEN 相同)。MapID为切片名;TYPE为该切片的数据类型;LEN为该切片的长度;CAP为该切片的总容量。CAP 可以理解为切片所引用的数组的长度,切片的长度不能超过容量 i.e.不能超过所引用的数组的长度。make()函数接受 2 个参数:元素的类型、切片的个数。

  • e.g.s2 := make([]int, 10)。定义了一个名为 s2,长度与容量都为 10 的整型切片
    • 这个例子可以拆解为两句,首先会声明一个数组var XX [10]int,然后使用该数组初始化一个切片var s2 []int = XX[:]Note:使用 make,而不是直接使用var persons []Person的声明方式。还是有所差别的,使用 make 的方式,当数组切片没有元素的时候,Json 会返回[]。如果直接声明,json 会返回 null

Slice 的引用

for-range 结构

使用该结构可以对数组或切片中的索引和元素的值进行相关操作,该结构可以返回索引与元素的值

格式:for INDEX,VAL := range SliceID {...}

返回值 INDEX 为数组或切片的索引;返回值 VAL 为该索引位置的值;MapID 为该数组或切片的名字代码示例:for-range.go\

Slice 的 reslice(重组)

在使用 make() 函数创建切片的时候,LEN 作为切片的初始长度,而 CAP 作为所切片所相关的数组的长度。这么做的好处是切片在达到 LEN 所定义的上限后,可以扩容,直到扩容到 CAP 定义的容量。改变切片长度的过程称之为切片的重组(reslicinig)

Slice 的追加 append() 与复制 copy()

append() 格式 1:SLICE2 := append(SLICE1, X1, X2...) df 把 X1,X2 等元素追加给切片 SLICE1,追加的元素必须和原切片的元素类型相同。如果 SLICE1 的容量不足以存储新增的元素,append 会分配新的切片来保证已有切片元素和新增元素的存储。因此,返回的切片可能已经指向一个不同的相关数组了。append 方法总是返回成功,除非系统内存耗尽了。

append 格式 2:SLICE2 := append(SLICE1, SLICE3)

可以将切片 SLICE3 追加到 SLICE1 的后面

copy 格式:copy(SLICE1, SLICE2)把切片 2 复制给切片 1

Slice 的删除

参考:

Go 语言并没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素,根据要删除元素的位置有三种情况,分别是从开头位置删除、从中间位置删除和从尾部删除,其中删除切片尾部的元素速度最快。

Go 语言中切片删除元素的本质是:以被删除元素为分界点,将前后两个部分的内存重新连接起来。

Go 语言中切片元素的删除过程并没有提供任何的语法糖或者方法封装,无论是初学者学习,还是实际使用都是极为麻烦的。

连续容器的元素删除无论是在任何语言中,都要将删除点前后的元素移动到新的位置。随着元素的增加,这个过程将会变得极为耗时。因此,当业务需要大量、频繁地从一个切片中删除元素时,如果对性能要求较高,就需要反思是否需要更换其他的容器(如双链表等能快速从删除点删除元素)。

seq := []string{"a", "b", "c", "d", "e"}
// 指定删除位置
index := 2
// 查看删除位置之前的元素和之后的元素
fmt.Println(seq[:index], seq[index+1:])
// 将删除点前后的元素连接起来
seq = append(seq[:index], seq[index+1:]...)
fmt.Println(seq)

代码输出结果: [a b] [d e] [a b d e] 第 1 行,声明一个整型切片,保存含有从 a 到 e 的字符串。 第 4 行,为了演示和讲解方便,使用 index 变量保存需要删除的元素位置。 第 7 行中:seq[:index] 表示的就是被删除元素的前半部分,值为: [1 2] seq[index+1:] 表示的是被删除元素的后半部分,值为: [4 5] 第 10 行使用 append() 函数将两个切片连接起来。 第 12 行,输出连接好的新切片。此时,索引为 2 的元素已经被删除。 代码的删除过程可以使用下图来描述。 image.png

排序

参考:

Go 的 sort 包可以对内置的数据类型以及自定义数据类型进行排序。通常都是作用在对应类型的数组、切片中。


最后修改 October 4, 2023: 合并 commit (98ba273b)