前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Go nil slice 空切片 区别
GoGo语言与并发

Go 的 nil 切片和空切片有什么区别,序列化和判空时各要注意什么?

nil切片是未初始化的切片,值为nil;空切片是已初始化但长度为0的切片。两者len均为0,但nil切片与nil比较为true,序列化时nil切片编码为null,空切片编码为[]。

前端进阶之旅 · 一题精讲更新于 2026.09.05
Go#语言与并发#并发编程
先看核心答案
理解线索

切片零值与空值

  1. nil切片var s []int,未初始化,指针为nil
  2. 空切片s:=[]int{},已初始化,长度0
  3. 判空标准len(s)==0对两者都成立

只有nil切片才能用s==nil判断,空切片不行。

核心回答

先记住这个答案

nil切片是var s []int,其内部指针为nil,长度和容量均为0。空切片是s := []int{}或make([]int,0),指针可能指向零数组。判空应使用len(s)==0而非s==nil。JSON序列化时,nil切片输出null,空切片输出[],这是最常见的差异。append对两者都有效,但nil切片在反射和某些库中需要特殊处理。

  • nil切片与nil比较为true,空切片为false
  • 判空用len(s)==0,不要用s==nil
  • JSON序列化nil为null,空为[]

内部结构与零值机制

切片在运行时是slice header,包含指向底层数组的指针、长度len和容量cap。当声明var s []int时,这三个字段均为零值,指针为nil,len和cap为0,因此s==nil成立。而空切片如s:=[]int{}或make([]int,0)会创建一个底层数组(可能长度0),指针非nil(可能指向runtime.zerobase),len和cap为0,所以s!=nil。但len(s)都是0,因此len判空更通用。

append对nil切片和空切片的行为类似,都会分配底层数组并返回新切片。但注意,append一个nil切片会分配底层数组,结果不再是nil。另外,reflect.ValueOf(s).IsNil()只对nil切片返回true,空切片返回false。这与接口的nil陷阱不同,因为切片本身是引用类型,但nil切片和空切片的底层指针不同。

JSON编码与前端数据填充场景

场景:后端Go API返回一个列表字段,当数据库查询无结果时,希望返回空数组[]而不是null,以方便前端直接遍历。若使用var items []Item,则序列化后为null;若使用items := []Item{}或make([]Item,0),则序列化为[]。决策是在构造响应时显式初始化空切片,而不是依赖默认零值。结果:前端能安全使用items.length而无需额外判断。

若忽略此差异,前端可能因items为null而报错。同样,在读取JSON时,null会被解析为nil切片,[]会被解析为空切片。因此,在反序列化后判空同样应使用len(s)==0,因为两者len为0,但nil切片与空切片在反射或部分库中可能表现不同,需要额外处理。

适用边界与易错条件

容易失效的条件是:当使用第三方库或反射时,库可能区分nil和空切片。例如encoding/json的Marshal就区分输出,而数据库驱动扫描NULL与空值也可能有不同语义,但切片类型通常不直接扫描,需借助JSON等序列化。如果库将空切片视为无记录,可能与nil混淆。所以对业务数据,明确约定空结果返回空切片还是nil,避免依赖库的默认行为。

处理方式:在API入口统一转换,如对查询结果做defensive check,若nil则赋值为[]。代价是额外分配,但可忽略。另一种方式是文档中明确不依赖JSON类型,但前端仍需处理null。建议在持久化或传输层统一为[]语义。

回答前,多想一步

容易答错的地方

用s==nil判断切片是否为空
错误,因为空切片s:=[]int{} s!=nil但len=0。正确应使用len(s)==0,这样对nil和空都有效。只适用于需要区分nil的场合才用s==nil。
认为nil切片不能append
实际上append对nil切片有效,会分配底层数组并返回新切片。但要注意,原nil切片不会被修改,需接收返回值。这与其他语言不同。
试着用自己的话回答

面试官还会怎么问?

nil切片和空切片的性能有差别吗?

性能差异微乎其微。nil切片不分配底层数组,空切片可能分配零大小的数组或指向zerobase。在循环中反复append时,nil切片首次append会分配,空切片可能已有容量但通常也需分配。关键看是否追加元素。

JSON反序列化时如何区分字段缺失和空数组?

字段缺失时,切片保持零值nil;空数组时得到空切片。若要区分,需使用指针类型比如*[]int,但通常无必要。可用自定义UnmarshalJSON。

数据库查询结果返回NULL时,切片会是什么?

database/sql并不直接支持扫描到切片,通常需扫描到[]byte或string后再解析。若通过JSON解析,NULL对应nil,空数组对应空切片。建议在业务层统一转换,避免依赖数据库默认值。

从一道题,走向一组知识

把知识连起来

语言与并发

Go 切片的 len 和 cap 分别决定什么,reslice 时各自起什么约束?

同属「语言与并发」专题,接着看 Go slice len cap 区别 在具体场景中的处理方式。

语言与并发

Go 对大切片取子切片后为什么会造成内存无法释放,如何避免?

同属「语言与并发」专题,接着看 Go 子切片 内存泄漏 底层数组 在具体场景中的处理方式。

参考资料

  • Effective Go

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 内部结构与零值机制
  3. JSON编码与前端数据填充场景
  4. 适用边界与易错条件
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑