声明和初始化
声明的原则是:
- 指明存储数据的类型
- 指明存储元素的数量,也就是数组长度
var array [5]int
以上我们声明了一个数组 array
,但是并没有进行初始化,这时候数组 array
里面的值,是对应元素类型的零值,也就是说,现在这个数组是 5个 0。
数组一旦声明后,其元素类型和大小就都不能变了,如果还需要存储更多的元素怎么办?那只能通过创建一个新的数组,然后把原来数组的数据复制过去。
刚刚声明的数组已经被默认的元素类型零值初始化了,如果想再次进行初始化操作,可以采用如下办法:
var array [5]int
array = [5]int{1, 2, 3, 4, 5}
Go 还为我们提供了 :=
操作符,可以让我们在创建数组的同时进行初始化:
array := [5]int{1, 2, 3, 4, 5}
有时我们连数组的长度都不想指定,可以直接使用 ...
代替,Go 会自动推导出数组的长度:
array := [...]int{1, 2, 3, 4, 5}
只给索引为 1 和 3 的数组元素初始化相应的值,其他都为 0,直接的办法:
array := [5]int{0, 2, 0, 4, 0}
更好的办法,只初始化索引 1 和 3 的值:
array := [5]int{1: 2, 3: 4}
由于长度也是数组类型的一部分,因此 [5]int 与 [4]int 是不同的类型。同样类型的数组是可以相互赋值的,不同类型的不行,会编译错误。Go 语言规定,必须是长度一样,并且每个元素的类型也一样的数组,才是同样类型的数组。
array := [5]int{1: 2, 3: 4}
var array1 [5]int = array // success
var array2 [4]int = array1 // error
指针数组
指针数组和数组本身差不多,只不过元素类型是指针。
array := [5]*int{1: new(int), 3: new(int)}
这样就创建了一个指针数组,并且为索引 1 和 3 分配了内存空间,其他索引是指针的零值 nil
,要修改指针变量的值,如下:
array := [5]*int{1: new(int), 3: new(int)}
*array[1] = 2
需要注意的是,只可以给索引 1 和 3 赋值,因为只有被分配了内存,才可以赋值。如果给索引 0 赋值,运行的时候,会提示无效内存或者是一个 nil
指针引用:
panic: runtime error: invalid memory address or nil pointer dereference
要解决这个问题,可以先给索引 0 分配内存,然后再进行赋值:
array := [5]*int{1: new(int), 3: new(int)}
array[0] = new(int)
*array[0] = 1
多维数组
// 声明一个二维数组,该数组以两个数组作为元素,其中每个数组中又有4个int类型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// 简化上面的声明,直接忽略内部的类型
doubleArray2 := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
函数间传递数组
在函数间传递变量时,总是以值的方式。如果变量是个数组,就会复制整个数组,并传递给函数,如果数组非常大,那对内存是一个很大的开销。
func main() {
array := [5]int{1, 2, 3, 4, 5}
modify(array)
fmt.Println(array)
}
func modify(a [5]int) {
a[0] = 100
fmt.Println(a)
}
可以看到,数组是复制的,原来的数组没有修改。
上面的例子是 5 个长度的数组还好,如果数组长度有几百万怎么办?有一种办法是传递数组的指针,这样,复制的大小只是一个数组类型的指针。
func main() {
array := [5]int{1, 2, 3, 4, 5}
modify(&array)
fmt.Println(array)
}
func modify(a *[5]int) {
a[0] = 100
fmt.Println(*a)
}
这是传递数组的指针的例子,会发现数组被修改了。这种情况虽然节省了复制的内存,但是要谨慎使用,因为一不小心,就会修改原数组,导致不必要的问题。
注意:数组的指针和指针数组是两个概念,数组的指针是
*[5]int
,指针数组是[5]*int
,注意*
的位置。
总结:当把一个数组作为参数传入函数的时候,传入的其实是该数组的副本,而不是它的指针。如果
要使用指针,那就需要使用 slice 类型。