一个数组具有固定的大小,这是其类型的一部分;一个切片是一个灵活的、动态大小的视图,用于查看底层数组。实际上,你几乎总是使用切片——数组在日常 Go 编程中很少见。
数组——固定大小
go
arr []
arr[] =
fmt.Println((arr))
数组的大小在编译时固定,并且是其类型的一部分([5]int ≠ [3]int)。数组也是值类型——赋值或传递数组会复制整个数组。这种严格性也是为什么它们很少被直接使用。
s := []int{1, 2, 3} // a slice (no size in the brackets)
s = append(s, 4) // grow it — append returns a new slice
fmt.Println(len(s), cap(s)) // length and capacity
nums := make([]int, 0, 10) // make a slice: length 0, capacity 10 (pre-allocated)
切片没有固定大小——你可以用 append 来增长它。它是首选的动态序列。
A slice is a small struct: { pointer to underlying array, length, capacity }
- len = number of elements currently in the slice
- cap = size of the underlying array from the slice's start
append: if len < cap, reuses the array; if len == cap, allocates a BIGGER array & copies
original := []int{1, 2, 3, 4, 5}
sub := original[1:3] // [2, 3] — a VIEW into the same backing array
sub[0] = 99 // ⚠️ also changes original[1] → [1, 99, 3, 4, 5]!
切片操作(s[low:high])不会复制——它创建一个指向同一个底层数组的新切片头。修改其中一个可能会影响另一个——这是细微错误的常见来源。使用 copy() 来进行独立复制。
a := []int{1, 2, 3}
b := append(a, 4) // may or may not share a's array depending on capacity
// safe pattern: always use the RETURNED slice from append
a = append(a, 4)
切片是 Go 中使用最频繁且最容易被误解的特性之一。
理解数组是固定大小的值类型(很少直接使用),而切片是灵活的、类似引用的视图(日常工具)是基础。
至关重要的是,了解共享底层数组行为——切片操作创建视图而非副本,因此修改可能影响其他切片,并且 append 可能会也可能不会重新分配——可以防止一类细微的、难以调试的别名问题,这些问题甚至会困扰经验丰富的开发者。
掌握切片(len vs cap、append、copy、共享陷阱)是必不可少的日常 Go 知识,也是常见的面试话题,因为几乎所有集合操作都使用它们。