[golang]slice类型nil和空切片的区别

本文探讨了Go语言中vara[]int和a:=make([]int,0)的用法差异,重点在于json序列化时的null与[]的区别,并通过内存结构解析来揭示其底层原理。实测结果显示两者在内存分配上的关键差异,对开发者在实际操作中的考量提供指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

日常使用中,var a []inta := make([]int, 0)的用法是比较频繁的,多数情况下两者可以互换,一般来说如果接下来的操作是append的话,两者几乎没有区别。

日常使用时的影响

  • 从日常实践角度来说,两者在使用时影响最大的区别是在json序列化时,前者会序列化为null,这个在前端解析中会异常;后者解析为[],如果涉及到前端交互时,两种用法还是得区分下
  • 判断问题,首先两者是不等的;其次在判断是否空时,建议统一使用len(a)==0做判断

不同的原因

下面对这两种情况为什么会有如此区别做解释,我们都知道slice在golang中内存结构如下

type slice struct {
   array unsafe.Pointer // 指向具体的数据地址
   len   int // 切片数量
   cap   int // 切片容量
}

那么我们就看看两种情况下对应的字段值是啥。编写测试代码(代码见文末)打印两种情况下相应内存字段值如下图所示
在这里插入图片描述
可以看到第二种情况下array字段指向一个地址,这个地址比较特殊,凡是所有的空slice都是指向这个地址,凡是所有的空结构体指针也是指向这个地址,这个地址其实是一个全局变量zerobase,在runtime.malloc.go文件中定义的

// runtime/malloc.go
var zerobase uintptr
...	
// 零内存空间分配时代码
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
  if size == 0 {
    return unsafe.Pointer(&zerobase)
 }
 ...

其存在于地址中0xc000092e88

在这里插入图片描述

测试代码

type slice struct {
   array unsafe.Pointer
   len   int
   cap   int
}
type empty struct{}

func main() {
   var a []int // a=nil
   p := (*slice)(unsafe.Pointer(&a))
   fmt.Printf("a.array %x\n", uintptr(p.array))
   fmt.Printf("a.len %v\n", uintptr(p.len))
   fmt.Printf("a.cap %v\n", uintptr(p.cap))
   b := make([]int, 0)
   pb := (*slice)(unsafe.Pointer(&b))
   fmt.Printf("b.array %x\n", uintptr(pb.array))
   fmt.Printf("b.len %v\n", uintptr(pb.len))
   fmt.Printf("b.cap %v\n", uintptr(pb.cap))
   c := make([]string, 0)
   pc := (*slice)(unsafe.Pointer(&c))
   fmt.Printf("c.array %x\n", uintptr(pc.array))
   fmt.Printf("c.len %v\n", uintptr(pc.len))
   fmt.Printf("c.cap %v\n", uintptr(pc.cap))
   d := new(empty)
   fmt.Printf("empty addr %x\n", uintptr(unsafe.Pointer(d)))
}

测试结果

a.array 0
a.len 0
a.cap 0
b.array c000092e88
b.len 0
b.cap 0
c.array c000092e88
c.len 0
c.cap 0
empty addr c000092e88
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值