
在 go 中,`make([]int, 0)`、`[]int{}` 和 `var s []int` 三种方式均可创建语义等价的空切片,均不触发内存分配;差异仅在于底层指针状态(nil vs 非-nil)及 json 序列化行为。
Go 提供了三种惯用方式来声明一个长度为 0、容量可动态增长的切片,它们在绝大多数运行时行为上完全一致:
- mySlice1 := make([]int, 0)
- mySlice2 := []int{}
- var mySlice3 []int
✅ 功能等价性:三者长度(len)均为 0,均可直接用于 append,且首次追加元素时会自动分配底层数组(如 append(mySlice1, 42))。Go 运行时对这三种形式做了高度优化,均不会提前分配底层数组内存——即无冗余堆分配,性能无差异。
✅ 代码示例验证:
package main
import "fmt"
func main() {
s1 := make([]int, 0)
s2 := []int{}
var s3 []int
fmt.Println(len(s1), cap(s1), s1 == nil) // 0 0 false
fmt.Println(len(s2), cap(s2), s2 == nil) // 0 0 false
fmt.Println(len(s3), cap(s3), s3 == nil) // 0 0 true ← 唯一区别在此
}注意:仅 var s []int 创建的是 nil 切片(底层指针为 nil),而前两者生成的是非-nil但长度为 0 的切片(底层指针非空,但指向零长数组)。
⚠️ 关键区别:JSON 序列化行为
这是实际开发中最易踩坑的点:
import "encoding/json"
data1 := []int{} // 非-nil 空切片
data2 := []int(nil) // 显式转为 nil 切片(等价于 var s []int)
b1, _ := json.Marshal(data1) // → "[]"
b2, _ := json.Marshal(data2) // → "null"因此,若 API 要求空数组必须序列化为 [](而非 null),应避免使用 var s []int;反之,若需与 null 语义对齐(例如表示“字段未设置”),则 nil 切片更合适。
? 最佳实践建议:
- ✅ 优先使用 []int{}:语法简洁、意图清晰、社区共识度高,是 Go 代码审查中最推荐的写法;
- ✅ 需要明确 nil 语义时,用 var s []int:适用于需与 nil 比较或控制 JSON 输出的场景;
- ⚠️ 避免过度使用 make(..., 0):虽合法,但冗余(make 更适用于需预设容量的场景,如 make([]int, 0, 16))。
总结:三者皆“正确”,但 []int{} 是最符合 Go 习惯、可读性最高、且无副作用的默认选择。










