[Go] 数组, 切片的长度与容量
Posted by clannadzsy ‐ Updated ‐ 1 min read
来源: Capacity and length of a slice in Go。下面补齐声明及共享底层数组的示例,语义以 Go 语言规范为准。
适用环境:仅使用标准库,在 Go 1.23.3、Windows/amd64 验证。完整示例保存为 main.go 后运行 go run main.go。
数组
数组是固定长度、元素类型相同的序列,声明形式为 var name [size]type。

数组的属性
- 长度是数组类型的一部分,
[4]int和[5]int是不同类型,不能直接相互赋值或比较。 - 未显式初始化的元素为其类型的零值,例如
var a [4]int的四个元素均为0。 - 数组赋值或作为值参数传递会复制数组值。若元素本身是指针等引用性数据,这不是递归的深拷贝。
- 元素类型可比较时,相同类型的数组可用
==比较;切片的比较规则不同。
切片
声明形式为 var name []type。

切片的属性
len(s)是当前切片的元素个数,cap(s)是从起点到其底层数组末端可容纳的元素个数。var s []int声明一个 nil 切片,长度与容量均为0;[]int{}是非 nil 的空切片,长度与容量也可以为0。切片只能直接与nil比较,不能使用a == b比较两个切片。- 切片赋值会复制切片值,两份切片最初共享底层数组;修改共享范围内的元素会互相可见。
append返回新的切片值,必须接收返回结果。容量足够时可能继续使用原数组;容量不足时分配新数组,后续修改不再影响原数组。具体扩容倍数是实现细节。
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
b := a
b[0] = 9
fmt.Println(a, b) // [1 2 3] [9 2 3]
s := make([]int, 2, 3)
s[0], s[1] = 1, 2
shared := s
shared[0] = 9
fmt.Println(s) // [9 2]
grown := append(s, 3) // 原容量为 3,仍能使用同一底层数组。
grown[1] = 8
fmt.Println(s, grown) // [9 8] [9 8 3]
detached := append(grown, 4) // 长度超过原容量,分配新的底层数组。
detached[0] = 7
fmt.Println(grown, detached) // [9 8 3] [7 8 3 4]
var nilSlice []int
emptySlice := []int{}
fmt.Println(len(nilSlice), cap(nilSlice), nilSlice == nil) // 0 0 true
fmt.Println(len(emptySlice), cap(emptySlice), emptySlice == nil) // 0 0 false
}
输出应与注释一致。不要根据某一次扩容后的容量推导固定扩容算法;这里仅用“超过原容量”保证示例中最后一次 append 必须分配新数组。