👨‍💻簡介

陣列就像是一個儲存相同類型資料的容器,你可以想像成裝滿了一樣東西的盒子,每個東西都叫做陣列元素。這種類型可以是基本的,像是整數或字串,也可以是你自己定義的型別。不過陣列有個限制,就是大小一旦確定就無法改變。在Go語言裡,陣列的長度也是型別的一部分。舉例來說,[5]int和[10]int就是不同的型別。雖然它們都是整數陣列,但因為長度不同,所以視為不同的資料型別,不能直接互相給值或操作。這麼做是為了在長度上更加嚴謹,不會混淆不同大小的陣列,增加了資料的安全性。

另一個類似的東西是切片(Slice),這東西可以想像成動態的序列,可以根據需要自由地增加或減少。不過,為了更好地理解切片,我們先學學陣列的使用。

陣列的基本概念

陣列是由一組元素所組成的固定大小的資料結構,每個元素都有一個相應的索引。陣列的大小在宣告時就需要確定,並且在後續操作中無法改變。

宣告和初始化陣列

在 Go 中,宣告和初始化陣列可以使用以下的語法:

var arr1 [3]int               // 創建一個整數陣列,大小為 3
arr2 := [4]string{"A", "B"}  // 創建一個包含 4 個字串元素的陣列
arr3 := [...]int{1, 2, 3}    // 自動推斷陣列大小為 3

你也可以在宣告陣列的同時,使用指定索引的方式來初始化陣列:

arr := [...]int{1: 10, 3: 30} // 陣列的值為 [0 10 0 30]

陣列的基本操作

取得陣列元素

陣列的元素可以通過索引來存取,索引從 0 開始計數。

numbers := [5]int{10, 20, 30, 40, 50}
firstNumber := numbers[0] // 存取第一個元素,值為 10
secondNumber := numbers[1] // 存取第二個元素,值為 20

假設我們有一個陣列 arr := [5]int{1, 2, 3, 4, 5}

  1. arr[:] 表示整個陣列:
arr := [5]int{1, 2, 3, 4, 5}
arr_new := arr[:]
fmt.Println(arr_new)  // 輸出:[1 2 3 4 5]
  1. arr[i:] 表示從索引 i 到陣列末尾的陣列:
arr := [5]int{1, 2, 3, 4, 5}
startIndex := 2
arr_new := arr[startIndex:]
fmt.Println(arr_new)  // 輸出:[3 4 5]
  1. arr[:i] 表示從陣列開頭到索引 i-1 的切片:
arr := [5]int{1, 2, 3, 4, 5}
endIndex := 3
arr_new := arr[:endIndex]
fmt.Println(arr_new)  // 輸出:[1 2 3]

修改陣列元素

我們可以修改陣列中的元素,例如:

var arr = [...]int{1, 2, 3}
arr[0] = 5
fmt.Println(arr)  // 輸出:[5 2 3]

遍歷陣列

可以使用傳統的索引方式或 range 來遍歷陣列中的元素:

numbers := [5]int{10, 20, 30, 40, 50}

// 使用傳統的索引方式遍歷陣列
for i := 0; i < len(numbers); i++ {
    fmt.Println(numbers[i])
}

// 使用 range 遍歷陣列
for _, num := range numbers {
    fmt.Println(num)
}

for i := range numbers {
    fmt.Println(numbers[i])
}

range 是一個內建函式,用於遍歷陣列、切片、映射等集合型資料。在這個範例中,我們使用 range 來遍歷 numbers 陣列中的每個元素,並將每個元素的值賦值給 num 變數。

陣列的特性、限制與使用場景

陣列的特性

  • 固定大小: 陣列在宣告時需要確定大小,且大小不可改變。這意味著一旦陣列被創建,其大小將保持不變。
  • 相同類型元素: 陣列內的元素必須是相同的類型,可以是內建的基本數據類型(如整數、浮點數)或自定義的結構體。
  • 連續儲存: 陣列中的元素在記憶體中是連續儲存的,這有助於提高存取效率,因為 CPU 可以預取接下來的元素。
  • 值類型: 陣列是值類型,當陣列被賦值給另一個陣列時,實際上是對數據的複製,而不是引用。

陣列是值類型,這意味著當你賦值或傳遞陣列時,實際上是複製整個陣列的內容。因此,對副本的修改不會影響原始陣列的值:

var array1 = [...]int{1, 2, 3}
array2 := array1
array2[0] = 3
fmt.Println(array1, array2)  // 輸出:[1 2 3] [3 2 3]

這上面的代碼展示了陣列的值類型特性。改變array2的值並不會影響array1的值。

陣列的限制

  • 固定大小: 陣列在宣告時需要指定固定的大小,且無法在運行時動態改變。這意味著陣列的容量是固定的,可能會限制資料集合的彈性。
  • 資源浪費: 如果分配了比實際使用更大的陣列,可能會浪費記憶體。而若分配比需求小的陣列,可能會限制數據的存儲。
  • 不適合動態資料: 由於固定大小,陣列不太適合儲存動態增減的資料集合,這方面切片(Slice)更適合。

使用場景

  • 固定大小需求: 當你確定資料集合的大小是固定的,且不會變動時,陣列是一個不錯的選擇,如一週的天數、一個月的天數等。
  • 簡單的資料儲存: 如果你僅需要儲存一些數值,且不需要動態調整大小,陣列可以很好地滿足需求。
  • 記憶體效能要求: 陣列在記憶體中是連續儲存的,這可以提供更好的存取效能,特別是當資料量較小時。
  • 多維資料: 陣列可以用於建立多維資料結構,例如矩陣,如果資料的結構相對固定,陣列是一個不錯的選擇。
  • 資料安全性: 陣列的大小固定,這可以防止意外的資料溢位,有助於維護資料的安全性。

常見用法

  • 取得陣列長度 使用內建函式len()即可取得陣列長度
var a[10]int
fmt.Println(len(a))
  • 計算陣列元素總和
numbers := [5]int{10, 20, 30, 40, 50}
var sum int

for _, num := range numbers {
    sum += num
}

fmt.Println("總和:", sum) // 輸出總和:150
  • 計算陣列元素平均值
numbers := [5]float64{98, 93, 77, 82, 83}
var sum float64

for _, num := range numbers {
    sum += num
}

average := sum / float64(len(numbers))
fmt.Printf("平均值:%.2f\n", average) // 輸出平均值:86.60
  • 尋找最大和最小值
numbers := [5]int{10, 20, 30, 40, 50}
max := numbers[0]


min := numbers[0]

for _, num := range numbers {
    if num > max {
        max = num
    }
    if num < min {
        min = num
    }
}

fmt.Println("最大值:", max) // 輸出最大值:50
fmt.Println("最小值:", min) // 輸出最小值:10
  • 陣列反轉
numbers := [5]int{10, 20, 30, 40, 50}
reversedNumbers := [5]int{}

for i, j := 0, len(numbers)-1; i < len(numbers); i, j = i+1, j-1 {
    reversedNumbers[j] = numbers[i]
}

fmt.Println("反轉陣列:", reversedNumbers) // 輸出反轉陣列:[50 40 30 20 10]

小結

陣列在Go語言中是一個基本的資料結構,用來固定儲存相同類型的元素。雖然使用受限,但在需要保持順序和固定大小的資料集合時非常實用。它在儲存資料、計算總和、平均值等方面扮演重要角色。陣列能透過索引初始化,特定位置賦值,其他位置保留預設值。無論使用索引或range,都能輕鬆迭代陣列元素,進行各種操作。陣列值需相同類型,且在記憶體中連續儲存,存取效率高。但記住,陣列大小固定,儲存可變數量元素可考慮使用切片。

📚Reference