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 相关题目🔗 开始刷题。

延伸阅读