聲明和初始化
聲明的原則是:
- 指明存儲(chǔ)數(shù)據(jù)的類型
- 指明存儲(chǔ)元素的數(shù)量,也就是數(shù)組長度
var array [5]int
以上我們聲明了一個(gè)數(shù)組 array
盗忱,但是并沒有進(jìn)行初始化,這時(shí)候數(shù)組 array
里面的值,是對應(yīng)元素類型的零值科阎,也就是說辆苔,現(xiàn)在這個(gè)數(shù)組是 5個(gè) 0算灸。
數(shù)組一旦聲明后,其元素類型和大小就都不能變了驻啤,如果還需要存儲(chǔ)更多的元素怎么辦菲驴?那只能通過創(chuàng)建一個(gè)新的數(shù)組,然后把原來數(shù)組的數(shù)據(jù)復(fù)制過去骑冗。
剛剛聲明的數(shù)組已經(jīng)被默認(rèn)的元素類型零值初始化了赊瞬,如果想再次進(jìn)行初始化操作,可以采用如下辦法:
var array [5]int
array = [5]int{1, 2, 3, 4, 5}
Go 還為我們提供了 :=
操作符贼涩,可以讓我們在創(chuàng)建數(shù)組的同時(shí)進(jìn)行初始化:
array := [5]int{1, 2, 3, 4, 5}
有時(shí)我們連數(shù)組的長度都不想指定巧涧,可以直接使用 ...
代替,Go 會(huì)自動(dòng)推導(dǎo)出數(shù)組的長度:
array := [...]int{1, 2, 3, 4, 5}
只給索引為 1 和 3 的數(shù)組元素初始化相應(yīng)的值遥倦,其他都為 0谤绳,直接的辦法:
array := [5]int{0, 2, 0, 4, 0}
更好的辦法,只初始化索引 1 和 3 的值:
array := [5]int{1: 2, 3: 4}
由于長度也是數(shù)組類型的一部分袒哥,因此 [5]int 與 [4]int 是不同的類型缩筛。同樣類型的數(shù)組是可以相互賦值的,不同類型的不行堡称,會(huì)編譯錯(cuò)誤瞎抛。Go 語言規(guī)定,必須是長度一樣却紧,并且每個(gè)元素的類型也一樣的數(shù)組桐臊,才是同樣類型的數(shù)組。
array := [5]int{1: 2, 3: 4}
var array1 [5]int = array // success
var array2 [4]int = array1 // error
指針數(shù)組
指針數(shù)組和數(shù)組本身差不多啄寡,只不過元素類型是指針豪硅。
array := [5]*int{1: new(int), 3: new(int)}
這樣就創(chuàng)建了一個(gè)指針數(shù)組,并且為索引 1 和 3 分配了內(nèi)存空間挺物,其他索引是指針的零值 nil
懒浮,要修改指針變量的值,如下:
array := [5]*int{1: new(int), 3: new(int)}
*array[1] = 2
需要注意的是,只可以給索引 1 和 3 賦值砚著,因?yàn)橹挥斜环峙淞藘?nèi)存次伶,才可以賦值。如果給索引 0 賦值稽穆,運(yùn)行的時(shí)候冠王,會(huì)提示無效內(nèi)存或者是一個(gè) nil
指針引用:
panic: runtime error: invalid memory address or nil pointer dereference
要解決這個(gè)問題,可以先給索引 0 分配內(nèi)存舌镶,然后再進(jìn)行賦值:
array := [5]*int{1: new(int), 3: new(int)}
array[0] = new(int)
*array[0] = 1
多維數(shù)組
// 聲明一個(gè)二維數(shù)組柱彻,該數(shù)組以兩個(gè)數(shù)組作為元素,其中每個(gè)數(shù)組中又有4個(gè)int類型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// 簡化上面的聲明餐胀,直接忽略內(nèi)部的類型
doubleArray2 := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
函數(shù)間傳遞數(shù)組
在函數(shù)間傳遞變量時(shí)哟楷,總是以值的方式。如果變量是個(gè)數(shù)組否灾,就會(huì)復(fù)制整個(gè)數(shù)組卖擅,并傳遞給函數(shù),如果數(shù)組非常大墨技,那對內(nèi)存是一個(gè)很大的開銷惩阶。
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)
}
可以看到,數(shù)組是復(fù)制的扣汪,原來的數(shù)組沒有修改断楷。
上面的例子是 5 個(gè)長度的數(shù)組還好,如果數(shù)組長度有幾百萬怎么辦私痹?有一種辦法是傳遞數(shù)組的指針脐嫂,這樣,復(fù)制的大小只是一個(gè)數(shù)組類型的指針紊遵。
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)
}
這是傳遞數(shù)組的指針的例子账千,會(huì)發(fā)現(xiàn)數(shù)組被修改了。這種情況雖然節(jié)省了復(fù)制的內(nèi)存暗膜,但是要謹(jǐn)慎使用匀奏,因?yàn)橐徊恍⌒模蜁?huì)修改原數(shù)組学搜,導(dǎo)致不必要的問題娃善。
注意:數(shù)組的指針和指針數(shù)組是兩個(gè)概念,數(shù)組的指針是
*[5]int
瑞佩,指針數(shù)組是[5]*int
聚磺,注意*
的位置。
總結(jié):當(dāng)把一個(gè)數(shù)組作為參數(shù)傳入函數(shù)的時(shí)候炬丸,傳入的其實(shí)是該數(shù)組的副本瘫寝,而不是它的指針蜒蕾。如果
要使用指針,那就需要使用 slice 類型焕阿。