認識 Go 語言中的數組

數組是具備相同惟一類型的一組已編號長度固定的數據項序列。git

聲明方式

在 Go 語言中,數組的聲明方式爲 var identifier [len]typegithub

聲明時沒有指定數組的初始化值,所以全部的元素都會被自動初始化爲默認值 0編程

// 聲明一個數組
var a1 [5]int
複製代碼

Go 語言中的數組是值類型,所以還能夠用 new 來建立:數組

var a2 = new([5]int)
複製代碼

new 返回類型的指針,所以 a1a2 的區別在於:a1 的類型爲 [5]inta2 的類型爲 *[5]intbash

初始化方法

咱們經過在 {} 中填寫初始化值來初始化數組。ide

指明數組長度

指明數組的長度 len,而後在 {} 中填寫初始化值,這些值會按下標從小到大的順序分配。函數

初始化值的個數不容許超過長度 len。當初始化值的個數小於 len 時,未被初始化的位置等於默認值 0。post

// 數組長度爲 5,初始化了前兩個數,未初始化的位是 0
b := [5]int{1, 2} 
for index, val := range b {
	fmt.Printf("下標 = %d, 值 = %d\n", index, val)
}

/* Output: 下標 = 0, 值 = 1 下標 = 1, 值 = 2 下標 = 2, 值 = 0 下標 = 3, 值 = 0 下標 = 4, 值 = 0 */
複製代碼

也可使用 {index1: a, index2: b} 的方式初始化數組,指明數組的索引和對應的下標值,未指明的下標所在位置的值等於默認值 0:學習

// 經過數組索引初始化
// d[0] = 1, d[2] = 3,其餘位置等於 0
d := [5]int{0: 1, 2: 3} 
for index, val := range d {
	fmt.Printf("下標 = %d, 值 = %d\n", index, val)
}

/* Output: 下標 = 0, 值 = 1 下標 = 1, 值 = 0 下標 = 2, 值 = 3 下標 = 3, 值 = 0 下標 = 4, 值 = 0 */
複製代碼

暗示數組長度

初始化時你也能夠不直接指明數組的長度,而是使用 [...] 代替。和指明數組長度時相同,此時也可使用順序填寫和指定索引兩種方式來初始化數組。ui

當使用 {a, b, c} 方式傳遞初始化值時,Go 語言將經過初始化元素的個數來肯定數組的長度

// 經過傳遞初始化值肯定數組長度
// 傳遞了 5 個元素,數組長度爲 5
c := [...]int{1, 2, 3, 4, 5}  
for index, val := range c {
	fmt.Printf("下標 = %d, 值 = %d\n", index, val)
}
/* Output: 下標 = 0, 值 = 1 下標 = 1, 值 = 2 下標 = 2, 值 = 3 下標 = 3, 值 = 4 下標 = 4, 值 = 5 */
複製代碼

若經過指明數組的索引和對應的值來初始化數組,此時數組的長度就等於 最大索引數 + 1

// 最大索引是 9,因此數組的長度爲 10
e := [...]int{9: 10} 
for index, val := range e {
	fmt.Printf("下標 = %d, 值 = %d\n", index, val)
}

/* Output:
下標 = 0, 值 = 0
下標 = 1, 值 = 0
下標 = 2, 值 = 0
下標 = 3, 值 = 0
下標 = 4, 值 = 0
下標 = 5, 值 = 0
下標 = 6, 值 = 0
下標 = 7, 值 = 0
下標 = 8, 值 = 0
下標 = 9, 值 = 10
*/
複製代碼

數組的遍歷

在 Go 語言中使用 for ... range 遍歷數組:

// i 是數組索引
for i, _ := range arr1 {
    // do something
}
複製代碼

數組是值類型

和 C/C++ 不一樣,Go 語言的數組是值類型的。這樣一來,賦值和傳參都會複製整個數組,而不是指針

咱們初始化一個數組 a,並把它賦值給數組 b,而後打印二者的值與指針:

a := [5]int{1, 2, 3, 4, 5}
b := a
fmt.Printf("數組 a - 值:%v,指針:%p\n", a, &a)
fmt.Printf("數組 b - 值:%v,指針:%p\n", b, &b)
/* Output:
數組 a - 值:[1 2 3 4 5],指針:0xc00001e0f0
數組 b - 值:[1 2 3 4 5],指針:0xc00001e120
*/
複製代碼

能夠看到,二者的值是相同的,可是內存地址卻不一樣,說明在賦值的過程當中複製了整個數組

咱們再來看一下傳參的例子。

定義一個函數 transmitA,把剛纔咱們初始化的數組 a 傳入:

func main() {
	a := [5]int{1, 2, 3, 4, 5}
	fmt.Printf("數組 a - 值:%v,指針:%p\n", a, &a)
	
	// 把數組 a 傳入函數
	transmitA(a)
}

func transmitA(a [5]int) {
	fmt.Printf("傳入函數的數組 a - 值:%v,指針:%p\n", a, &a)
}

/* Output: 數組 a - 值:[1 2 3 4 5],指針:0xc00001e0f0 傳入函數的數組 a - 值:[1 2 3 4 5],指針:0xc00001e150 */
複製代碼

從輸出能夠看出,二者的值依然相同,內存地址倒是不一樣的。這說明在傳參時數組也被複制了

數組指針與指針數組

數組指針與指針數組聽起來彷佛有點拗口,那麼來展開說明一下:

  • 數組指針:(指向)數組(的)指針
  • 指針數組:(裝滿了)指針(的)數組

也就是說,數組指針是個指針,它指向一個數組;而指針數組是個數組,它裏面裝滿了指針

數組指針

聲明一個數組 a,而後將它的地址賦值給 arrayPointer。這樣一來,arrayPointer 就是一個指向數組 a 的指針,即數組指針,它的類型爲 *[5]int

a := [5]int{1, 2, 3, 4, 5}
// 把數組 a 的地址賦值給 arrayPointer
// arrayPointer 是指向數組的指針,類型爲 *[5]int
arrayPointer := &a
fmt.Println(arrayPointer)

/* Output: &[1 2 3 4 5] */
複製代碼

指針數組

初始化數組 pointerArray,傳入的初始化值爲整型 mn 的內存地址(&m&n),那麼 pointerArray 就是一個裝着 int 類型指針的數組,即指針數組,它的類型爲 [2]*int

m := 1
n := 2
// 初始化 pointerArray,傳入 m 與 n 的地址
// pointerArray 包含了整型地址,是一個裝着指針的數組
pointerArray := [2]*int{&m, &n}
fmt.Println(pointerArray)

/* Output: [0xc0000aa000 0xc0000aa008] */
複製代碼

總結

  • 數組的長度是固定的,初始化時須要「明示」或「暗示」數組的長度
  • 數組的長度是數組類型的組成部分[2]int[100]int 是不一樣類型的數組
  • 使用 for ... range 遍歷數組
  • 在 Go 語言中,數組是值類型,賦值和傳遞參數都會發生數組的複製
  • 數組指針是一個指針,它指向了一個數組
  • 指針數組是一個數組,它裏面裝着指針

參考資料

往期回顧


若是你以爲文章寫得不錯,請幫我兩個小忙:

  1. 點贊並關注我,讓這篇文章被更多人看到
  2. 關注公衆號「編程拯救世界」,公衆號專一於編程基礎與服務端研發,你將第一時間得到新文章的推送~

你的鼓勵是我創做最大的動力,感謝你們!

相關文章
相關標籤/搜索