再經過了這麼多章節的探討go的基本原理後,我們今天要來面對的是go的資料結構,由於go的資料結構特別,所以我想要留到後面再來講,像是,我們熟悉的陣列,在go裡面其實有分成陣列和切片,他們的使用也有非常不一樣的地方
陣列是一組在記憶體中連續位置的資料結構,因為是連續位置,所以我們能透過所引來訪問
在初始化時,有兩種方式,取決於你知不知道這個陣列的大小
arr1 := [3]int{1, 2, 3}
arr2 := [...]int{1, 2, 3}
第一種是固定陣列長度,第二種是不固定
再來,我們先來看source code
func NewArray(elem *Type, bound int64) *Type {
if bound < 0 {
Fatalf("NewArray: invalid bound %v", bound)
}
t := New(TARRAY)
t.Extra = &Array{Elem: elem, Bound: bound}
t.SetNotInHeap(elem.NotInHeap())
return t
}
從這段source code我們可以得到幾種認知
bound
參數指定了陣列的大小。當你在 Go 中創建一個陣列,你需要指定它的大小,且一旦指定,其大小就不能更改
arr2 := [...]int{1, 2, 3}
{1, 2, 3}
為3,並指定elem
參數指定了陣列元素的類型。這確保了陣列中所有的元素都是同一類型bound
是否小於 0。這是一種確保不創建具有無效大小的陣列的方法。此檢查避免了潛在的錯誤或不正確的使用情況TARRAY
類型的物件,然後為它設置了與陣列相關的額外資料,這包括元素的類型 (Elem
) 和陣列的大小 (Bound
)Go 的 for
迴圈可以使用迭代器 (iterator)
package main
import (
"fmt"
)
func main() {
var arr [4]string
arr = [4]string{"q", "d", "aa", "cc"}
fmt.Println(arr)
for i, e := range arr {
fmt.Println(fmt.Sprintf("%d: %s", i+1, e))
}
}
如果要改變陣列裡面的元素的話可以這樣做
package main
import (
"fmt"
)
func main() {
var arr [4]string
arr = [4]string{"q", "d", "aa", "cc"}
fmt.Println(arr)
for i := 0; i < len(arr); i++ {
arr[i] = arr[i] + "aa"
}
fmt.Println(arr)
}
從上面可以發現go的陣列是把類型和大小綁在一起的,當你宣告完後go會開出你指定大小的連續記憶體空間,故如果你把長度為8的陣列塞到長度為5的陣列,那就會報錯
func printArray(a [5]int) {
fmt.Println(a)
}
func main() {
var example = [8]int{1, 2, 3, 4, 5, 6, 7, 8}
printArray(example)
}
此時編譯完後會顯示
var example [8]int
cannot use example (variable of type [8]int) as [5]int value in argument to printArraycompilerIncompatibleAssign
固定大小的陣列(array)一旦被定義,其大小就不能更改。這意味著你不能像在某些其他程式語言中那樣使用 push
或 pop
操作來動態地添加或移除元素
package main
import "fmt"
func main() {
initOnlySpecficIndex := [4]int{0: 3, 2: 4}
fmt.Println(initOnlySpecficIndex)
// [3,0,4,0]
}
計算陣列長度
len(
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
length := len(arr)
fmt.Println("Length of the array:", length)
}
Output:
Length of the array: 5
多為陣列
scores := [3][3]int{
{90, 85, 78}, // 學生 1 的分數
{76, 85, 88}, // 學生 2 的分數
{78, 90, 79}, // 學生 3 的分數
}