nil 切片是 var s []int 声明的零值,指针为 nil,len 和 cap 都是 0;空切片是 s := []int{} 或 make([]int, 0),有非 nil 的底层指针(指向 zerobase),len 为 0。两者在 len、cap、range、append 行为上完全一致,但 s == nil 的判定结果不同。
关键差异在序列化和接口约定:encoding/json 中 nil 切片编码为 null,空切片编码为 [],这在 API 契约里常造成前后端纠纷。SQL 驱动、部分 protobuf 场景也有类似区别。
工程建议:
- 函数返回切片时,无数据优先返回 nil,不要刻意构造空切片;
- 消费方永远不要依赖 s == nil 判断'没有元素',用 len(s) == 0 才安全;
- 对外 API 字段若要求 [],在序列化前做归一化。
var a []int
b := []int{}
fmt.Println(a == nil, b == nil) // true false
fmt.Println(len(a), len(b)) // 0 0
追问方向:nil map 能否读写(读可、写 panic)、接口 nil 判定的陷阱。