Go切片必须基于数组或已有切片创建,常用make(控制长度/容量)或字面量(初始化已知元素);支持截取生成共享底层数组的视图;需警惕nil/空切片差异、append扩容机制及底层数组生命周期问题。

Go语言中切片不能直接“创建”而必须基于底层数组(或已有切片)生成,最安全、最常用的方式是用 make 或字面量初始化。
用 make 创建带长度和容量的切片
这是控制内存分配最明确的方式,适用于需要预分配空间、避免频繁扩容的场景(比如批量读取文件、网络缓冲)。
-
make([]T, len):创建长度为len、容量也为len的切片,所有元素为零值 -
make([]T, len, cap):创建长度len、容量cap(cap >= len)的切片,超出len的部分不可访问但可被append复用 - 如果
len > cap,编译报错:len larger than cap in make([]T) - 容量影响
append性能:只要不超容,append是 O(1);一旦触发扩容(通常翻倍),会分配新底层数组并拷贝,开销变大
示例:
buf := make([]byte, 0, 1024) // 预留1KB容量,初始长度0,适合循环append
用字面量声明并初始化切片
适合已知初始元素的场景,简洁直观,底层自动调用 make 并赋值。
立即学习“go语言免费学习笔记(深入)”;
-
[]int{1, 2, 3}:长度和容量都为 3 -
[]string{"a", "b"}:类型由元素推导,无需显式写[]string(但在函数参数或变量声明中常需) - 空切片字面量
[]int{}和var s []int效果一致:长度 0、容量 0、底层数组为nil - 注意:
[3]int{1,2,3}是数组,不是切片;少一个[]就完全不是同一类型
从数组或已有切片截取生成新切片
这是切片“视图”特性的核心用法,不分配新底层数组(除非后续 append 触发扩容),共享内存。
-
arr[1:3]:从数组arr截取,新切片长度 =3-1,容量 =len(arr)-1 -
s[2:4:6]:三索引切片,显式指定新容量(上限为原容量减起始偏移),防止意外覆盖原数据 - 越界 panic:索引超出原切片/数组范围(如
s[10:]当len(s)==5)会 panic,运行时检查 - 修改新切片元素会反映到原底层数组——这是共享语义,也是常见 bug 来源(比如函数返回局部数组的切片,但数组栈上已失效)
常见误用与坑
很多问题源于混淆“零值切片”“nil 切片”和“空切片”,以及对底层数组生命周期的误判。
-
var s []int、s = nil、s = []int{}三者len/cap都是 0,但前两者s == nil为 true,最后一个为 false;json.Marshal对nil切片输出null,对空切片输出[] - 在循环中反复
append到同一个切片,却未重置(如s = s[:0]),会导致旧数据残留 - 函数接收
[]T参数时,内部append可能扩容并返回新底层数组,但调用方变量未更新——必须显式接收返回值:s = append(s, x) - 用
range遍历切片时,迭代变量是副本,修改它不影响原切片;要改元素得用索引:s[i] = ...
底层数组的生命周期只取决于是否有活跃的切片引用它——哪怕原始变量早已离开作用域,只要还有切片指向它,就不会被回收。这点和 C 的指针不同,也和 Java 的引用不同,容易在长期运行服务中引发意料外的内存驻留。










