数组 array
# 6. 数组 array
# 6.1 数组介绍
数组是指一系列同一类型数据的集合 。
数组中包含的每个数据被称为数组元素(element),这种类型可以是任意的原始类型,比如 int、string 等。
一个数组包含的元素个数被称为数组的长度。在 Golang 中数组是一个长度固定的数据类型,数组的长度是类型的一部分,也就是说 [5]int 和[10]int 是两个不同的类型 。
Golang中数组的另一个特点是占用内存的连续性,也就是说数组中的元素是被分配到连续的内存地址中的,因而索引数组元素的速度非常快。
和数组对应的类型是 Slice(切片),Slice 是可以增长和收缩的动态序列,功能也更灵活。
==var 数组变量名 [数组长度]T==
var arr [N]T
比如:var a [5]int, 数组的长度必须是常量,并且长度是数组类型的一部分,一旦定义,长度不能变。 [5]int 和[4]int 是不同的类型。
package main
import "fmt"
func main() {
// 定义一个长度为 5 元素类型为 int 的数组 a
var a [5]int
// 定义一个长度为 3 元素类型为 int 的数组 b 并赋值
var b [3]int
b[0] = 80
b[1] = 100
b[2] = 96
fmt.Println(a) // [0 0 0 0 0]
fmt.Println(b) // [80 100 96]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如果两个数组类型的元素类型 T 与元素数量 N 都是一样的,那么这两个数组类型是等价的,如果有一个属性不同,它们就是两个不同的数组类型。下面这个示例很好地诠释了这一点:
func foo(arr [5]int) {}
func main() {
var arr1 [5]int
var arr2 [6]int
var arr3 [5]string
foo(arr1) // ok
foo(arr2) // 错误:[6]int与函数foo参数的类型[5]int不是同一数组类型
foo(arr3) // 错误:[5]string与函数foo参数的类型[5]int不是同一数组类型
}
2
3
4
5
6
7
8
9
10
11
Go 提供了预定义函数 ==len== 可以用于获取一个数组类型变量的长度,通过 unsafe 包提供的 ==Sizeof== 函数,我们可以获得一个数组变量的总大小,如下:
var arr = [6]int{1, 2, 3, 4, 5, 6}
fmt.Println("数组长度:", len(arr)) // 6
fmt.Println("数组大小:", unsafe.Sizeof(arr)) // 48
2
3
# 6.2 多维数组
var mArr [2][3][4]int
将 mArr 这个数组看成是一个拥有两个元素,且元素类型都为[3] [4]int 的数组,就像图中最上层画的那样。这样,mArr 的两个元素分别为 mArr[0]和 mArr [1],它们的类型均为[3] [4]int,也就是说它们都是二维数组。
而以 mArr[0]为例,我们可以将其看成一个拥有 3 个元素且元素类型为[4]int 的数组,也就是图中中间层画的那样。这样 mArr[0]的三个元素分别为 mArr[0][0]、mArr[0][1]以及 mArr[0][2],它们的类型均为[4]int,也就是说它们都是一维数组。
图中的最后一层就是 mArr[0]的三个元素,以及 mArr[1]的三个元素的各自展开形式。以此类推,你会发现,无论多维数组究竟有多少维,我们都可以将它从左到右逐一展开,最终化为我们熟悉的一维数组。
数组在使用中的问题:数组类型变量是一个整体,这就意味着一个数组变量表示的是整个数组。这点与 C 语言完全不同,在 C 语言中,数组变量可视为指向数组第一个元素的指针。这样一来,无论是参与迭代,还是作为实际参数传给一个函数 / 方法,Go 传递数组的方式都是纯粹的值拷贝,这会带来较大的内存拷贝开销。可以使用切片来解决。
# 6.3 数组遍历
# 6.3.1 普通遍历数组
package main
import "fmt"
func main() {
var a = [...]string{"北京", "上海", "深圳"}
for i := 0; i < len(a); i++ {
fmt.Println(a[i])
}
}
/*
北京
上海
深圳
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 6.3.2 K/V遍历数组
package main
import "fmt"
func main() {
var a = [...]string{"北京", "上海", "深圳"}
for index, value := range a {
fmt.Println(index, value)
}
}
/*
0 北京
1 上海
2 深圳
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17