Slice 是动态数组,是在 Go 中处理数组的主要结构单位。历史上,编程语言提供了固定数组或更复杂的数据结构。Go 实现了 slices 作为处理内存集合的便捷工具,具有自动管理大小和修改长度的能力。
问题 在于如何正确管理内存,处理边界情况(空的、nil、满的 slices),以及理解 length 和 capacity 之间的区别。
解决方案 是正确使用内置函数 len()、cap(),并按照 Go 的约定操作 slices。
代码示例:
var a []int // nil slice,len=0,cap=0 b := make([]int, 0) // 空 slice,len=0,cap=0 c := make([]int, 3, 5) // len=3,cap=5 c = append(c, 4, 5, 6) // cap 将自动增加
关键特性:
var s []int) 并不分配内存,内部与空 slice (make([]int, 0)) 仅有差异。对 nil slice 进行 append 后,slice 的长度和容量会是多少?
Nil slice (var s []int) 在 append(s, 1) 后变为长度为 1,容量为 1 的 slice — Go 自动分配存储。
var s []int s = append(s, 42) // s 现在是 [42],len=1,cap=1
可以访问 nil slice 的 capacity 吗?
可以,nil slice 的两个函数 len 和 cap 返回 0。不会有 panic。
var s []int fmt.Println(len(s), cap(s)) // 0 0
在没有预先为 nil slice 分配内存的情况下尝试按索引赋值时,会发生什么?
会产生 panic index out of range,因为 slice 没有元素。
var s []int s[0] = 1 // panic: runtime error: index out of range
团队决定在 Go 服务器中处处使用 var s []T,期望这总是等同于 make([]T, 0)。结果导致一些 JSON 序列化返回 null 而不是 []。
优点:
缺点:
使用 make([]T, 0, 100) 进行预分配,然后在循环中仅使用 append。这样可以最小化内存分配,并常常提高性能。
优点:
缺点: