Go语言数组

Go语言数组

​ Go语言中提供了3种数据结构可以让用户管理集合数据:数组、切片和映射。这3中数据结构时语言核心的一部分。其中数组则是切片和映射的基础数据结构。

一、数组的内部实现和基础功能

1. 内部实现

​ 在Go语言中,数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块。数组存储的类型可以时内置类型,如整型或者字符串,也可以是某种结构类型。

图1.1 数组的内部实现
​ 如图1.1 是一个5位整型数组的表示,每一个灰色小格子代表数组里的一个元素,每个元素都紧邻这另一个元素,每个元素包含相同的类型——整型,每个元素都可以用一个唯一的索引(也叫做下标)来表示

​ 数组占用的内存是连续分配的,由于内存连续,CPU可以把正在使用的数据缓存更久的时间,且容易计算索引,可以快速迭代数组里的所有元素。数组的类型信息可以提供每次访问一个元素时需要在内存中移动的距离。

为什么类型可以提供移动距离?并没有想清楚,希望以后可以得到答案

2. 声明和初始化

声明数组的基本语法格式如下

1
var variable_name [SIZE] variable_type

​ 声明数组时需要指定内部存储的数据的类型,以及需要存储的元素的数量,也就是数组的长度。

1
2
// 声明一个包含5个元素的整型数组
var array [5]int
代码块1.1 声明一个数组并设置零值
​ 一旦声明,数组里存储的数据类型和数组长度就不能改变了,如果需要存储更多的元素,就需要先创建一个更长的数组,在将原来数组中的值拷贝过来。

​ 在Go语言中,声明变量时总会使用对应类型的零值来对变量进行初始话,数组也不例外。当数组初始化时,数组内的每个元素都初始化为对应类型的零值。 如上声明的5位整型数组,其每个元素都会被初始化为0,也就是整型的零值。

图1.2 初始化后的数组
​ 一种快速创建数组并初始化的方式是使用数组字面量。 数组字面量允许声明数组里元素的数量同时指定每个元素的值。
1
2
// 声明一个5为整型数组,并用具体值初始化每一个元素
arr := [5]int{1,2,3,5,6}

​ 如果是用...代替数组长度,Go语言会根据初始化时数组元素的数量来确定该数组的长度。

1
2
// 声明一个整型数组,用具体值初始化每一个元素,数组长度由初始化值的数量确定
arr := [...]int{1,3,5,6,7}

​ 如果知道数组的长度,并且准备个特定位置的元素指定具体值,可以使用如下方法

1
2
3
// 声明一个5位整型数组,用具体值初始化下标为1,3的元素
arr := [5]int{1:23, 3:234}
// 得到的数组为 [0,23,0,234,0]

3. 使用数组

  • 访问数组元素

要访问数组里单独的元素,需要使用[]运算符。

1
2
3
4
5
// 声明一个5为整型数组,并用具体值初始化每一个元素
arr := [5]int{1,2,3,5,6}

// 修改数组下标为3的元素值
arr[3] = 123
  • 访问指针元素

声明一个所有元素都是指针的的数组,使用*运算符就可以访问元素指针所指向的值

1
2
var arr4 = [5]*int {1:new(int),3:new(int)}
*arr4[1] = 1;
  • 数组赋值

Go语言中,数组是一个值,可以用在赋值操作中,变量名代表整个数组,同样类型的数组可以赋值给另一个数组

1
2
3
var arr5 [5]string
arr6 := [5]string{"1","2","3","4","6"}
arr5 = arr6

复制之后两个数组的值完全一样。

​ 数组的类型包括数组长度和每个值的类型,只有这两个部分完全一样,才是类型相同的数组,才可以相互赋值。编译器会阻止不同类型的数组相互赋值。

  • 指针数组复制

复制指针数组,只会复制指针的值(内存地址),而不会复制指针所指向的值。

4. 多维数组

声明方式

1
var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type

如声明3维数组

1
2
3
var threedim [4][3][3]int

// [[[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]] [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]] [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]]

访问多维数组的元素

1
threedim[2][2][1] = 3

和一维数组一样,只要类型一致,多维数组也可相互赋值

5.函数间传递数组

从内存和性能的角度来看,在函数间传递数组是一项开销很大的操作。go语言在函数间传递变量时,总是以值的方式传递的。如果这个变量是一个数组,意味着整个数组,不管有多长,都会完整复制并传递给函数。为了更有效的利用内存和更好的性能,可以在传递时只传递指向数组的指针。但是,如果改变指向指针的值,会改变共享的内存。此时,使用切片可以更好的处理这类共享问题。