var s []int声明的是nil切片,底层数组未分配,s == nil为true;而s := []int{}创建的是非nil空切片,底层数组已分配,s == nil为false,二者json序列化结果分别为null和[]。

声明空切片但不分配底层数组
直接用 var 声明切片变量,不初始化,此时值为 nil,长度和容量都是 0,且底层指针为 nil:
var s []int
这种写法适合后续用 make 或字面量赋值,也适合函数参数接收可选切片。注意:对 nil 切片调用 len、cap 是安全的,但不能直接索引或用 append(除非配合 make 初始化)。
用 make 创建有底层数组的切片
需要立即分配内存并指定初始长度和容量时,必须用 make:
s := make([]int, 3) // 长度=3,容量=3,元素全为零值<br>s := make([]int, 3, 5) // 长度=3,容量=5,预留扩容空间
make 返回的是引用类型值,不是指针;第二个参数是 len,第三个是 cap(可省略,默认等于 len)。常见错误是把 make([]int, 5) 当作“创建 5 个未初始化元素”,其实它创建了 5 个零值 int。
立即学习“go语言免费学习笔记(深入)”;
用字面量声明并初始化切片
适用于已知初始元素的场景,编译器自动推导类型和长度:
s := []int{1, 2, 3} // 类型明确,长度=3,容量=3<br>s := []string{"a", "b"} // 同理
注意:[]int{} 创建的是非 nil 空切片(底层数组存在,长度=0,容量=0),和 var s []int 的 nil 切片行为不同——比如 json.Marshal 对前者输出 [],对后者输出 null。
声明切片变量时容易忽略的细节
切片是结构体(包含指针、长度、容量),但声明时不涉及内存分配,只声明变量本身。容易踩的坑包括:
- 误以为
var s []int和s := []int{}等价 —— 前者是nil,后者不是 - 在循环中反复
make([]int, 0)而不复用,导致频繁分配小数组 - 声明时写成
var s []int = make([]int, 0),冗余且掩盖了nil与空切片的区别 - 混淆
[]T(切片类型)和[N]T(数组类型),后者长度是类型的一部分,不可变
真正关键的不是“怎么写”,而是“要不要立刻分配”和“是否允许为 nil”。这两点决定了后续操作的安全边界和序列化表现。


















