Slicce vs Array in Go

Go Slice vs Array 差異與底層原理

Slice vs Array´

在 Go 語言中,有兩種常見的資料結構可用於表示「序列資料」:Array 與 Slice。 這兩者在語法上相似,但背後行為與使用情境差異非常關鍵。簡單來說,Array 是固定長度(Static Array),而 Slice 是動態長度(Dynamic Array)。

Array

// 宣告 5 個 int 的 Array
array := [5]int{1, 2, 3, 4, 5}
// 訪問或修改元素
array[0] = 100
// 讓 compiler 自動推斷陣列長度
b := [...]string{"Penn", "Teller"}

Slice

Slice 建立於 Array 之上,它並不直接存放資料,而是指向底層 Array,同時記錄目前的長度與容量。

func main() {
// 建立 Slice(長度 3,容量 5)
s := make([]int, 3, 5)
fmt.Println(s, len(s), cap(s)) // [0 0 0] 3 5
// 修改與讀取
s[0] = 10
s[1] = 20
s[2] = 30
// 擴充
s = append(s, 40, 50)
fmt.Println(s, len(s), cap(s)) // [10 20 30 40 50] 5 5
// 擴充
s = append(s, 60)
fmt.Println(s, len(s), cap(s)) // [10 20 30 40 50 60] 6 10
// 子 Slice 切片
sub := s[1:4]
fmt.Println(sub) // [20 30 40]
}

了解 Slice 的自動擴充機制

當對 Slice 執行 append 時:

  • 若底層 Array 還有空間 → 直接延伸長度(O(1))
  • 若容量不足 → Go 會建立一個更大的 Array,將舊資料複製過去(O(n))
func main() {
// 均攤分析 Amortized analysis
s := []int{1}
fmt.Println(len(s), cap(s)) // 1 1, O(1)
s = append(s, 1)
fmt.Println(len(s), cap(s)) // 2 2, O(1)
s = append(s, 1)
fmt.Println(len(s), cap(s)) // 3 4, O(n)
s = append(s, 1)
fmt.Println(len(s), cap(s)) // 4 4, O(1)
s = append(s, 1)
fmt.Println(len(s), cap(s)) // 5 8, O(n)
}

可以看到容量大多倍增成長,這樣的自動擴容策略兼顧了效能與記憶體利用率。

Range

遍歷陣列內容。

func main() {
s := []string{"apple", "banana", "cherry"}
for i, v := range s {
fmt.Println(i, v)
}
}
// 0 apple
// 1 banana
// 2 cherry

: 切片

: 用來擷取 Slice 部分區間,格式為 slice[low:high] 代表從索引 low 開始(包含),直到索引 high 結束(不包含):

func main() {
s := []int{10, 20, 30, 40, 50}
fmt.Println(s[1:3]) // [20 30]
fmt.Println(s[:2]) // [10 20],省略前界代表 0
fmt.Println(s[2:]) // [30 40 50],省略後界代表 len(s)
}

s[a:b] 雖然是創建一個新的 Slice,但仍共用相同的底層 array,修改 sub Slice 的內容,會影響原始資料:

sub := s[1:3]
sub[0] = 99
fmt.Println(s) // [10 99 30 40 50]
fmt.Println(sub) // [99 30]

Copy

由於 Slice 共用底層 Array,若要建立完全獨立的副本,應使用 copy()

s := []int{1, 2, 3}
t := make([]int, len(s))
copy(t, s)
t[0] = 99
fmt.Println(s) // [1 2 3]
fmt.Println(t) // [99 2 3]

總結

比較項目ArraySlice
長度固定可變
型別定義[N]T[]T
是否含容量資訊
是否可擴充是(append)
傳遞開銷複製整個陣列傳參考(輕量)
適用場景已知固定長度不確定長度、需彈性增減資料

可到 Codewars 找 Go Array 相關題目🔗 開始刷題。

延伸閱讀