Slice vs Array´
在 Go 語言中,有兩種常見的資料結構可用於表示「序列資料」:Array 與 Slice。 這兩者在語法上相似,但背後行為與使用情境差異非常關鍵。簡單來說,Array 是固定長度(Static Array),而 Slice 是動態長度(Dynamic Array)。
Array
// 宣告 5 個 int 的 Arrayarray := [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] = 99fmt.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] = 99fmt.Println(s) // [1 2 3]fmt.Println(t) // [99 2 3]總結
| 比較項目 | Array | Slice |
|---|---|---|
| 長度 | 固定 | 可變 |
| 型別定義 | [N]T | []T |
| 是否含容量資訊 | 否 | 是 |
| 是否可擴充 | 否 | 是(append) |
| 傳遞開銷 | 複製整個陣列 | 傳參考(輕量) |
| 適用場景 | 已知固定長度 | 不確定長度、需彈性增減資料 |
可到 Codewars 找 Go Array 相關題目 開始刷題。
延伸閱讀
- Go Slices: usage and internals - go.dev
- [Golang] Array and Slice - PJCHENder
- If you are a beginner in Go, avoid this Slice pitfall! - Flo Woelki
- Go Class: 10 Slices in Detail - Matt KØDVB