Golang容器之数组

133 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

一、概述

数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组。

和数组对应的类型是 Slice(切片),Slice 是可以增长和收缩的动态序列,功能也更灵活,但是想要理解 slice 工作原理的话需要先理解数组,所以本节主要为大家讲解数组的使用。

二、数组

2.1 声明数组

数组的声明语法如下:

var 数组变量名 [元素数量]Type

说明

  • 数组变量名:数组声明及使用时的变量名。
  • 元素数量:数组的元素数量,可以是一个表达式,但最终通过编译期计算的结果必须是整型数值,元素数量不能含有到运行时才能确认大小的数值。
  • Type:可以是任意基本类型,包括数组本身,类型为数组本身时,可以实现多维数组。

注意

数组的长度是数组类型的一个组成部分,因此 [3]int[4]int 是两种不同的数组类型,数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定。

q := [3]int{1, 2, 3}
q = [4]int{1, 2, 3, 4} // 编译错误:无法将 [4]int 赋给 [3]int

2.2 数组初始化

方式一

初始化数组时可以使用初始化列表来设置数组元素的值。

func test01(){
	var testArray [3]int                        //数组会初始化为int类型的零值
	var numArray = [3]int{1, 2}                 //使用指定的初始值完成初始化
	var cityArray = [3]string{"北京", "上海", "深圳"} //使用指定的初始值完成初始化
	fmt.Println(testArray)                      //[0 0 0]
	fmt.Println(numArray)                       //[1 2 0]
	fmt.Println(cityArray)                      //[北京 上海 深圳]
}

func main() {
	test01()
}

默认情况下,数组的每个元素都会被初始化为元素类型对应的零值,对于数字类型来说就是 0,同时也可以使用数组字面值语法,用一组值来初始化数组。

方式二

在数组的定义中,如果在数组长度的位置出现“...”省略号,则表示数组的长度是根据初始化值的个数来计算,因此,上面数组的定义可以简化为:

func test02(){
	var numArray = [...]int{1, 2}
	var cityArray = [...]string{"北京", "上海", "深圳"}
	fmt.Println(numArray)                           //[1 2]
	fmt.Printf("type of numArray:%T\n", numArray)   //type of numArray:[2]int
	fmt.Println(cityArray)                          //[北京 上海 深圳]
	fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string
}

func main() {
	test02()
}
方式三

可以通过指定索引,方便地对数组某几个元素赋值

func test03(){
	a := [...]int{1: 1, 3: 5}
	fmt.Println(a)                  // [0 1 0 5]
	fmt.Printf("type of a:%T\n", a) //type of a:[4]int
}

func main() {
	test03()
}

2.3 相关操作

数组的遍历
func test04(){
	var a = [...]string{"北京", "上海", "深圳"}
	// 方法1:for循环遍历
	for i := 0; i < len(a); i++ {
		fmt.Println(i,a[i])
	}
	fmt.Println("---------------")
	// 方法2:for range遍历
    //index:数组中元素的索引
    //value:数组的每个元素值
	for index, value := range a {
		fmt.Println(index, value)
	}
}

func main() {
	test04()
}

运行结果

0 北京
1 上海
2 深圳
---------------
0 北京
1 上海
2 深圳
比较两个数组是否相等

如果两个数组类型相同(包括数组的长度,数组中元素的类型)的情况下,我们可以直接通过较运算符(==!=)来判断两个数组是否相等,只有当两个数组的所有元素都是相等的时候数组才是相等的,不能比较两个类型不同的数组,否则程序将无法完成编译。

func test05(){
	a := [2]int{1, 2}
	b := [...]int{1, 2}
	c := [2]int{1, 3}
	fmt.Println(a == b, a == c, b == c) // "true false false"
	d := [3]int{1, 2}
	fmt.Println(a == d) // 编译错误:无法比较 [2]int == [3]int
}

func main() {
	test05()
}

三、多维数组

Go语言中允许使用多维数组,因为数组属于值类型,所以多维数组的所有维度都会在创建时自动初始化零值,多维数组尤其适合管理具有父子关系或者与坐标系相关联的数据。

3.1 声明多维数组

语法如下所示:

var array_name [size1][size2]...[sizen] array_type
  • array_name:数组的名称
  • array_type:数组的类型
  • [size1][size2]...[sizen]:为数组每一维度的长度

3.2 初始化

  • 声明一个二维数组,并赋初值
// 声明一个二维整型数组,两个维度的长度分别是 4 和 2
var array [4][2]int

// 使用数组字面量来声明并初始化一个二维整型数组
array = [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}

// 声明并初始化数组中索引为 1 和 3 的元素
array = [4][2]int{1: {20, 21}, 3: {40, 41}}

// 声明并初始化数组中指定的元素
array = [4][2]int{1: {0: 20}, 3: {1: 41}}

下图展示了上面示例中声明的二维数组在每次声明并初始化后包含的值。

05.GO语言容器之数组02.gif

  • 为二维数组的每个元素赋值
// 声明一个 2×2 的二维整型数组
var array [2][2]int
// 设置每个元素的整型值
array[0][0] = 10
array[0][1] = 20
array[1][0] = 30
array[1][1] = 40
  • 同样类型的多维数组赋值

多维数组的类型包括每一维度的长度以及存储在元素中数据的类型。

// 声明两个二维整型数组
var array1 [2][2]int
var array2 [2][2]int

// 为array2的每个元素赋值
array2[0][0] = 10
array2[0][1] = 20
array2[1][0] = 30
array2[1][1] = 40

// 将 array2 的值复制给 array1
array1 = array2
  • 使用索引为多维数组赋值

因为数组中每个元素都是一个值,所以可以独立复制某个维度

// 将 array1 的索引为 1 的维度复制到一个同类型的新数组里
var array3 [2]int = array1[1]

// 将数组中指定的整型值复制到新的整型变量里
var value int = array1[1][0]

3.3 二维数组的遍历

func test06(){
	a := [3][2]string{
		{"北京", "上海"},
		{"广州", "深圳"},
		{"成都", "重庆"},
	}
	for _, v1 := range a {
		for _, v2 := range v1 {
			fmt.Printf("%s\t", v2)
		}
		fmt.Println()
	}
}

func main() {
	test06()
}

运行结果

北京	上海	
广州	深圳	
成都	重庆

注意: 多维数组只有第一层可以使用...来让编译器推导数组长度。

例如:

//支持的写法
a := [...][2]string{
	{"北京", "上海"},
	{"广州", "深圳"},
	{"成都", "重庆"},
}
//不支持多维数组的内层使用...
b := [3][...]string{
	{"北京", "上海"},
	{"广州", "深圳"},
	{"成都", "重庆"},
}

附参考文章链接

www.liwenzhou.com/posts/Go/05…

c.biancheng.net/view/4117.h…