GoLang - 数组
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列(这是一种同构的数据结构);这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
WARNING
数组长度必须是一个常量表达式,并且必须是一个非负整数。
一维数组
一维数组声明以及初始化常见方式如下:
var arrAge = [5]int{18, 20, 15, 22, 16}
// 指定索引位置初始化
var arrName = [5]string{3: "Chris", 4: "Ron"} // ["","","","Chris","Ron"]
// 指定索引位置初始化
var arrCount = [4]int{500, 2: 100} // [500,0,100,0]
// 数组长度初始化时根据元素多少确定
var arrLazy = [...]int{5, 6, 7, 8, 22}
// 指定索引位置初始化,数组长度与此有关
var arrPack = [...]int{10, 20, 30, 4: 5, 40} // [10 20 30 0 5 40]
var arrRoom [20]int
var arrBed = new([20]int)
数组在声明时需要确定长度,但是也可以采用上面不定长数组的方式声明,在初始化时会自动确定好数组的长度。上面 arrPack
声明中 len(arrPack)
结果为 6 ,表明初始化时已经确定了数组长度。而 arrRoom
和 arrBed
这两个数组的所有元素这时都为 0
,这是因为每个元素是一个整型值,当声明数组时所有的元素都会被自动初始化为默认值 0
。
Go 语言中的数组是一种值类型(不像 C/C++ 中是指向首元素的指针),所以可以通过 new()
来创建:
var arr1 = new([5]int)
那么这种方式和 var arr2 [5]int
的区别是什么呢?arr1
的类型是 *[5]int
,而 arr2
的类型是 [5]int
。
TIP
数组长度也是数组类型的一部分,所以 [5]int
和 [10]int
是属于不同类型的。
package main
import "fmt"
func main() {
var arr1 = new([5]int)
arr := arr1
arr1[2] = 100
fmt.Println(arr1[2], arr[2])
var arr2 [5]int
newarr := arr2
arr2[2] = 100
fmt.Println(arr2[2], newarr[2])
}
输出结果:
100 100
100 0
从上面代码结果可以看到,new([5]int)
创建的是数组指针,arr
其实和 arr1
指向同一地址,故而修改 arr1
时 arr
同样也生效。而 newarr
是由 arr2
值传递(拷贝),故而修改任何一个都不会改变另一个的值。在写函数或方法时,如果参数是数组,需要注意参数长度不能过大。
由于把一个大数组传递给函数会消耗很多内存(值传递),在实际中我们通常有两种方法可以避免这种现象:
- 使用数组的指针
- 使用切片
通常使用切片是第一选择。
多维数组
多维数组在Go语言中也是支持的,例如:
// len() 长度根据实际初始化时数据的长度来定,这里为2
[...][5]int{ {10, 20}, {30, 40} }
// len() 长度为3
[3][5]int
// 可以这样理解 [2]([2]([2]float64))
[2][2][2]float64
TIP
在定义多维数组时,仅第一维允许使用 …
,而内置函数 len
和 cap
也都返回第一维度长度。定义数组时使用 …
表示长度,表示初始化时的实际长度来确定数组的长度。
b := [...][5]int{ { 10, 20 }, { 30, 40, 50, 60 } }
fmt.Println(b[1][3], len(b)) //60 2
数组元素可以通过索引(下标)来读取(或者修改),索引从 0
开始,第一个元素索引为 0
,第二个索引为 1
,以此类推。(数组以 0
开始在所有类 C 语言中是相似的)。元素的数目,也称为长度或者数组大小必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组大小最大为 2 GB。
遍历数组的方法既可以 for
条件循环,也可以使用 for-range
。这两种 for
结构对于切片(slices
)来说也同样适用。
TIP
另外,如数组元素类型支持 ==
,!=
操作符,那么数组也支持此操作,但如果数组类型不一样则不支持(需要长度和数据类型一致,否则编译不通过)。