Go | 初步了解「陣列」型別
💬 簡介
在程式語言中,陣列是最基本的複合型別之一。它用來儲存多個相同類型的資料項目,這些項目擁有連續的記憶體位置。你可以將陣列想像成一個有序的資料集合,當需要處理多個相似元素時,陣列提供了一種簡單且高效的解決方案。
本文將介紹陣列的基本概念,並展示一些常見的使用範例。
圖片來源:Gophers(地鼠造型的原創者為 Renee French)
✨ 陣列的基本概念
陣列是一個固定大小的資料結構,裡面存放著相同類型的元素。這些元素的索引通常從 0 開始,且可以直接透過索引來訪問。
1️⃣ 陣列的宣告與初始化
你可以使用方括號 []
來宣告一個陣列,並指定陣列的大小。陣列的大小在宣告時已經確定,因此是不可變的。
- 範例:陣列的宣告與初始化
1
var numbers [5]int
📝 這樣我們就創建了一個可以儲存 5 個整數的陣列,並且初始化為預設值 0。
- 範例:直接在創建陣列時進行初始化
1
numbers := [5]int{1, 2, 3, 4, 5}
📝 這樣我們就創建了一個可以儲存 5 個整數的陣列,並且初始化預設值
1, 2, 3, 4, 5
。
2️⃣ 訪問陣列元素
你可以通過索引來訪問陣列中的元素,索引從 0 開始:
- 範例:
1
2fmt.Println(numbers[0]) // 輸出: 1
fmt.Println(numbers[4]) // 輸出: 5
3️⃣ 陣列的長度
陣列的長度是固定的,可以使用 len 函式來獲取陣列的長度:
- 範例:
1
fmt.Println(len(numbers)) // 輸出: 5
🛠️ 範例:基本陣列操作
1️⃣ 定義陣列並初始化
- 範例:
1
2
3
4
5
6
7
8
9
10
11
12package main
import "fmt"
func main() {
var fruits [3]string
fruits[0] = "Apple"
fruits[1] = "Banana"
fruits[2] = "Cherry"
fmt.Println(fruits) // 輸出: [Apple Banana Cherry]
}📝 在這個範例中,展示了如何定義一個陣列並初始化其元素。
2️⃣ 使用簡化的初始化
- 範例:
1
2
3
4
5
6
7
8package main
import "fmt"
func main() {
colors := [3]string{"Red", "Green", "Blue"}
fmt.Println(colors) // 輸出: [Red Green Blue]
}📝 在這個範例中,展示了如何使用簡單的語法來初始化陣列。
3️⃣ 傳遞陣列到函式
- 範例:
1
2
3
4
5
6
7
8
9
10
11
12
13package main
import "fmt"
func changeFirstElement(arr [3]int) {
arr[0] = 100
}
func main() {
nums := [3]int{1, 2, 3}
changeFirstElement(nums)
fmt.Println(nums) // 輸出: [1 2 3] (原始陣列不變)
}📝 在這個範例中,當我們將陣列作為參數傳遞時,陣列的副本會被傳遞給函式。
💡 進階使用
↔️ 比對兩個陣列是否相等
範例:用
for
迴圈比較每個元素
有時候我們需要比對兩個陣列是否相等。由於陣列是固定大小的複合型別,我們可以簡單地用for
迴圈逐一比較每個元素。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package main
import "fmt"
func compareArrays(arr1, arr2 [3]int) bool {
for i := 0; i < len(arr1); i++ {
if arr1[i] != arr2[i] {
return false
}
}
return true
}
func main() {
array1 := [3]int{1, 2, 3}
array2 := [3]int{1, 2, 3}
array3 := [3]int{4, 5, 6}
fmt.Println(compareArrays(array1, array2)) // 輸出: true
fmt.Println(compareArrays(array1, array3)) // 輸出: false
}📝 在這個範例中,展示了如何比較兩個陣列是否相等。
範例:使用
==
比較兩個陣列是否相等1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package main
import "fmt"
func main() {
// 定義三個陣列
a := [2]int{1, 2}
b := [...]int{1, 2} // 使用省略號語法讓編譯器自動推斷大小
c := [2]int{1, 3} // 內容不同
d := [3]int{1, 2} // 長度不同
// 比較陣列 a, b 和 c
fmt.Println(a == b) // true, 兩個陣列相等
fmt.Println(a == c) // false, 內容不同
fmt.Println(b == c) // false, 內容不同
// 嘗試比較長度不同的陣列
fmt.Println(a == d) // 編譯錯誤:無法比較 [2]int == [3]int
}輸出:
1
2
3
4true
false
false
編譯錯誤:無法比較 [2]int == [3]int📝 詳解:
a == b
會返回true
,因為這兩個陣列的元素完全相同。a == c
和b == c
會返回false
,因為它們的元素不同(a
和b
中的第二個元素都是2
,而c
中是3
)。a == d
會產生編譯錯誤,因為a
和d
的長度不同,Go 不能比較不同長度的陣列。
🏁 補充:關於「省略號 (…)」:
在範例中,我使用了[...]int{1, 2}
來初始化陣列。這樣的寫法讓 Go 編譯器根據資料的長度自動推斷陣列的大小,這樣就不需要手動指定陣列的大小。這在某些情況下可以提高程式碼的可讀性。
🔄 使用 for
迴圈列印陣列
另一個常見的操作是使用 for
迴圈來遍歷陣列中的每個元素並進行處理。這對於顯示陣列中的所有項目特別有用。
範例:用
for
迴圈印出陣列的元素1
2
3
4
5
6
7
8
9
10
11package main
import "fmt"
func main() {
animals := [4]string{"Cat", "Dog", "Elephant", "Lion"}
for i := 0; i < len(animals); i++ {
fmt.Println(animals[i])
}
}📝 在這個範例中,展示了如何用
for
迴圈遍歷並印出陣列中的每個元素。範例:使用
range
簡化for
迴圈
在 Go 中,range
提供了一個更簡潔的方式來遍歷陣列或切片:1
2
3
4
5
6
7
8
9
10
11package main
import "fmt"
func main() {
cities := [3]string{"New York", "London", "Tokyo"}
for index, city := range cities {
fmt.Printf("Index %d: %s\n", index, city)
}
}📝 在這個範例中,我們使用
range
遍歷陣列並輸出每個城市的名稱和索引,第一個是元素的索引,第二個是該索引對應的元素值,在這個例子中,index 是陣列元素的索引,而 city 是對應的元素值。
❓ 為什麼選擇 range
?
- 簡潔性:
range
自動處理索引,讓程式碼更加簡單。 - 可讀性:透過
range
,程式邏輯更清晰,讀者能夠更容易理解程式的行為。 - 不易出錯:使用
range
避免了錯誤地引用索引或疏忽元素數量。📝 這就是在 Go 中遍歷陣列的最佳實踐,選擇
range
可以讓程式碼更加簡潔高效。
🚀 陣列的限制與優化
- 固定大小:陣列的大小在創建時就已經確定,因此無法動態改變。若需要動態大小的容器,可以考慮使用切片(slice)。
- 記憶體佔用:由於陣列的大小是固定的,這意味著如果預計的大小過大,可能會浪費空間;如果預計的大小過小,則可能會限制功能。
- 效能:由於陣列的元素是連續存放的,這使得它在記憶體存取上更為高效。
🎯總結
陣列是一種簡單且有效的資料結構,適用於存儲固定數量的元素。理解陣列的基本操作和限制能幫助你在適當的情境中選擇合適的資料結構,提升程式的效能和可讀性。
最後建議回顧一下 Go | 菜鳥教學 目錄,了解其章節內容。
註:以上參考了
Go
Go-Array types