Go 常見資料型別-01陣列

一個一個人發表於2022-11-09

前言

最近剛練習完GoAPI實戰,途中發現自己對Go各種資料型別的理解還是很淺薄,所以打算重新把Go各種資料型別的一些理解做一個整理,同時也分享給大家,初學者,理解淺薄,有不足的歡迎大家指出交流。

陣列的宣告:

陣列的宣告需要指定元素的資料型別,以及儲存元素的數量(陣列長度),如以下程式碼所示

var a [3]int
var b [4]int
a = b //不可以這樣做,因為此時a和b是不同的陣列型別

陣列長度必須是一個非負整數的常量(或常量表示式),陣列長度也是陣列型別的一部分,所以[3]int和[4]int不是同一種型別

陣列需要在宣告時指定陣列長度(編譯時需要知道陣列長度以便分配記憶體),陣列最大長度為2GB。

陣列一旦宣告,它所儲存的資料型別和陣列長度便都不能修改了。如果需要儲存更多的元素,必須先建立一個更長的陣列,然後把原來的陣列裡的值複製到新陣列裡面。

初始化陣列

陣列可以有多種初始化方式,如:

方式1

go 語言在宣告變數時,都是使用相應型別的零值來初始化變數的,陣列也一樣。陣列初始化時,其每個元素都被初始化對應型別的零值。比如下面的整形陣列裡,每個元素都被初始化為0(整形的零值)

var testArr [3]int             // 陣列會初始化為零值 [0 0 0]
var testArr = [3]int{1, 2}     // 陣列會將未指定的下標值初始化為0值 [1 2 0]
var testArr = [3]int{1, 2, 3}  // 陣列使用指定的資料初始化 [1 2 3]

方式2

以上的方式需要保證初始化的陣列長度和指定陣列長度一樣,除此以外我們還可以讓編譯器自己判斷陣列的長度

var testArr = [...]int{1, 2, 3}     // 陣列自動指定長度為3 [1 2 3]

方式3

此外還可以透過指定索引值的方式來初始化陣列:

var testArr = [...]int{1:20, 5: 30}  // [0 20 0 0 0 30]

陣列的操作

陣列訪問

對於陣列arr[],第一個元素是arr[0],第三個元素是arr[2],總體來說下標i代表的元素是arr[i],最後一個元素是arr[len(arr)-1],超出範圍會報panic。

陣列修改

GO語言透過陣列下標(索引位置)來讀取和修改陣列元素,下標(索引)從0開始,逐漸類推。

陣列是效率很高的資料結構,因為陣列在記憶體分配中是連續的,要訪問陣列裡某個單獨的值,使用[]運算子既可。
陣列的值也可以是指標,下面宣告一個所有元素都是指標的陣列,然後使用*運算子就可以訪問元素指標所指向的值:

// 宣告包含5個元素的指向整數的陣列
// 用整形指標初始化索引為0和1的陣列元素
array := [5]*int{0: new(int), 1: new(int)}
// 為索引0和1的元素賦值
*array[0] = 10
*array[1] = 20

fmt.Println(*array[0])
//輸出為:10

fmt.Println(*array[2])
// 報錯 panic: runtime error: invalid memory address or nil pointer dereference,因為此時 array[2] 沒有指定型別

陣列賦值

在GO語言中,陣列是一個型別值,這意味著陣列也可以像函式一樣用在賦值操作中,變數名代表整個陣列,因此同樣型別的陣列可以賦值類另一個陣列,如:

// 宣告一個包含5個元素的字串陣列
var array1 [5]string
// 宣告第二個包含5個元素的字串陣列並初始化
array2 := [5]string{"a", "b", "c", "d", "e"}
array1 = array2

陣列作為一個變數型別,它包括陣列長度和每個元素的型別兩個部分。只有兩部分都相同的陣列才是型別相同的陣列,才能相互賦值。

陣列的型別

陣列是值型別,賦值和傳參會複製整個陣列。因此改變副本的值,不會改變本身的值。

var array1 [3]string
array2 := [3]string{"", "", ""}

array2[0] = "a"
array2[1] = "b"
array2[2] = "c"
array1 = array2
array2[0] = "d"
fmt.Println(array1[0])
// 輸出a

而在下面操作中,複製操作後,兩個陣列指向同一組字串,修改其中一個陣列的某個值後,另一個陣列的值也相應改變。

// 宣告一個包含3個元素的指向字串的指標陣列
var array1 [3]*string
// 宣告第二個包含3個元素的指向字串的指標陣列,並使用字串指標初始化這個陣列
array2 := [3]*string{new(string), new(string), new(string)}
*array2[0] = "a"
*array2[1] = "b"
*array2[2] = "c"

array1 = array2
*array2[1] = "d"
fmt.Println(*array1[1])
// 輸出d

注意:

  • 陣列支援 “==“、”!=” 運算子,因為記憶體總是被初始化過的。
  • [n]*T表示指標陣列,*[n]T表示陣列指標.

多維陣列

陣列本身只有一個維度,但是可以組合多個陣列建立多維陣列。多維陣列用於管理具有依賴關係的資料(比如座標系),下面是宣告二維陣列的示例程式碼:

//宣告一個二維整形陣列,兩個維度分別儲存4個元素和2個元素
var array [4][2]int
//使用陣列字面量來宣告並初始化一個二維整形陣列
array := [4][2]int{{1, 2}, {3, 4}, {5, 6}, {7, 8}}
//宣告並初始化外層陣列中索引為1和3的元素
array := [4][2]int{1: {3, 4}, 3: {7, 8}}
//宣告並初始化外層陣列和內層陣列的單個元素
array := [4][2]int{1: {0: 1}, 3: {1: 2}}

訪問單個元素,需要組合[]運算子。如:

array[0][1] = 1

和一維陣列一樣,只要型別一致,就可以將多維陣列互相賦值,又因為每個陣列都是一個單獨的值,所以還可以獨立賦值某個維度,如:

// 將array1的索引為1的維度賦值到一個同型別的新陣列裡
var array3 [2]int = array1[1]
// 將外層陣列的索引為1、內層陣列的索引為0的整形值複製到新的整形變數裡
var value int = array1[1][0]

多維陣列也可以使用...來編譯器自動判斷陣列長度。但只支援第一層陣列這樣使用。如:

//支援的寫法
a := [...][2]string{
    {"北京", "上海"},
    {"廣州", "深圳"},
    {"成都", "重慶"},
}
//不支援多維陣列的內層使用...
b := [3][...]string{
    {"北京", "上海"},
    {"廣州", "深圳"},
    {"成都", "重慶"},
}

陣列的遍歷

一維陣列遍歷

func main() {
    var a = [...]string{"a", "b", "c"}
    // 方法1:for迴圈遍歷
    for i := 0; i < len(a); i++ {
        fmt.Println(a[i])
    }

    // 方法2:for range遍歷
    for index, value := range a {
        fmt.Println(index, value)
    }
}

二維陣列遍歷

func main() {
    a := [3][2]string{
        {"北京", "上海"},
        {"廣州", "深圳"},
        {"成都", "重慶"},
    }
    for _, v1 := range a {
        for _, v2 := range v1 {
            fmt.Printf("%s\t", v2)
        }
        fmt.Println()
    }
}

慢慢會把其它資料型別的也做一個整理,做一個合集,希望整理完對自己學習Go會有幫助。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章