首页 > 其他分享 >golang中的空切片和nil切片

golang中的空切片和nil切片

时间:2023-07-07 15:35:15浏览次数:27  
标签:golang nil int fmt 切片 Println var

Golang中的切片是很基本的数据结构,它的底层是一个数组,表层是一个包含三个变量的结构体:

type slice struct {

array unsafe.Pointer  //指针,指向底层的数组

length int  //切片的长度

capcity int  //切片的容量

}

当把一个切片赋值给另一个切片时,实际上是对切片表层结构体的浅拷贝。

 

在编写项目代码时遇到了切片的特殊状态,这里对其做一个比较总结:

 

l  零切片

[零切片]其实并不是一种特殊的切片,它表示切片底层数组的二进制内容都是0,如下的s就是一个零切片:

var s = make([]int, 10)

fmt.Println(s)

------------

[0 0 0 0 0 0 0 0 0 0]

 

l  空切片和nil切片

这两种特殊形态的切片容易混淆。

首先,我们看看长度为0的切片可以怎样创建:

var s1 []int

var s2 = []int{}

var s3 = make([]int, 0)

var s4 = *new([]int)  // new 函数返回是指针类型,所以需要使用 * 号来解引用

 

fmt.Println(len(s1), len(s2), len(s3), len(s4))

fmt.Println(cap(s1), cap(s2), cap(s3), cap(s4))  //切片容量

fmt.Println(s1, s2, s3, s4)

----------------

0 0 0 0

0 0 0 0

[] [] [] []

可以看到,这四种形式的输出结果一模一样。但实际上,s1和s4是[nil切片],s2和s3是[空切片],它们是有区别的。

研究这四种形式的内部结构,可以使用go语言中的高级内容——unsafe.Pointer来转换任意变量类型。

因为切片的内部结构是一个包含三个变量的结构体,第一个变量是一个指向内存地址的指针变量。我们可以将这个结构体看成长度为3的整形数组[3]int,用unsafe.Pointer来转换:

var a1 = *(*[3]int)(unsafe.Pointer(&s1))

var a2 = *(*[3]int)(unsafe.Pointer(&s2))

var a3 = *(*[3]int)(unsafe.Pointer(&s3))

var a4 = *(*[3]int)(unsafe.Pointer(&s4))

fmt.Println(a1)

fmt.Println(a2)

fmt.Println(a3)

fmt.Println(a4)

---------------------

[0 0 0]

[824634199592 0 0]

[824634199592 0 0]

[0 0 0]

       输出为[0 0 0]的就是[nil切片],而824634199592是一个特殊的内存地址,所有类型的[空切片]都共享这一个内存地址。

 

l  空切片和nil切片在使用上的注意事项

var s1 []int

var s2 = []int{}

 

fmt.Println(s1 == nil)

fmt.Println(s2 == nil)

 

-------

true

false

 

在写代码时,最好不要创建[空切片],统一使用[nil切片]。在将切片和nil进行比较来执行某些逻辑时要特别小心。

 

 

另外,这两种切片在JSON序列化时也不一样,涉及到的时候要注意。

 

 

标签:golang,nil,int,fmt,切片,Println,var
From: https://www.cnblogs.com/gongxianjin/p/17535118.html

相关文章

  • linux环境安装golang
    在使用pprof工具分析性能时,发现我们的环境上默认没有装go,所以执行不了gotoolpprof命令,于是自己手动装了下。步骤如下:首先下载一个对应系统架构的golang包,这里我用的是arm包,装的1.14.12版本。(见附件)。在环境上创一个个人目录,把包传上去,然后执行以下命令解压到/usr/local目录下(官......
  • Golang中的Channel(二)
    上篇介绍了Channel是什么以及它的类型,这篇总结一下Channel的用法。 基本语法(1)        声明channel声明channel的语法格式为:varChannelNamechanElementType与其他变量声明不同的是,在类型前面多了一个chan关键字。ElementType指的是这个channel能够传递的数据类......
  • Golang中的Channel(一)
    Golang在并发编程上有两大利器,分别是channel和goroutine。Golang中有一句名言:“使用通信来共享内存,而不是通过共享内存来通信”。这句话有两层意思,Go语言确实在sync包中提供了传统的锁机制,但更推荐使用channel来解决并发问题。这里先对Channel做一个基本的介绍,对于其深一层的实现......
  • Golang的类图
    @目录1.依赖(Dependency)1.1概念1.2代码示例1.3类图示例2.泛化(Generalization)-继承2.1概念2.2代码示例2.3类图3.泛化(Generalization)-实现3.1概念3.2代码示例3.3类图4.关联关系(Association)4.1概念4.2代码示例4.3类图5.聚合关系(Aggregation)5.1概念5.2代码示例5.3......
  • golang 解析yaml文件
    初始化packagemainimport( "github.com/spf13/viper")funcinitConfig(){ viper.SetConfigName("config") viper.AddConfigPath("./") iferr:=viper.ReadInConfig();err!=nil{ fmt.Println("Initsetingerror:",......
  • golang之http请求库go-resty
     github: https://github.com/go-resty/resty go-resty特性#go-resty 有很多特性:发起GET,POST,PUT,DELETE,HEAD,PATCH,OPTIONS,etc.请求简单的链式书写自动解析JSON和XML类型的文档上传文件重试功能客户端测试功能RestyclientCustom RootCertificates andC......
  • go 传参 类型:接口类型 返回统配接口类型 , 求两个切片并集
     用一个函数可以同时求两个[]string 切片,或者两个[]int切片并集packagemain//测试统配传参funccommonParamTest(s1,s2interface{})interface{}{switchv:=s1.(type){//获取对应的类型case[]string:m:=make(map[string]int)......
  • Golang起步篇
    一.安装Go语言开发环境1.Wondows下搭建Go开发环境(1).下载SDK工具包sdk下载地址为:https://go.dev/dl/(2).解压下载的压缩包,放到特定的目录下,我一般放在d:/programs下(路径不能有中文或者特殊符号如空格等)(3).配置环境变量步骤1:先打开环境变量配置的界面步骤2:配置......
  • golang解决go get下载失败解决办法
    原因:所下载的库依赖有官方库,而官方被封禁网导致。方法:设置代理goenv-wGOPROXY=https://goproxy.cnps:go1.11发布后,还发布一个goproxy提供代理服务,goproxy.cn是专门服务于中国的,依赖于七牛云github地址:https://github.com/goproxy......
  • golang汇编学习(寄存器)
    好久没有写博客了,上一篇写的汇编只是简单的调试了一下,这段时间又看了下,做一个简单的汇总。两个代码汇编代码,1_amd64.sTEXT·add(SB),$0-0MOVQa+0(FP),AXMOVQb+8(FP),BXADDQAX,BXMOVQBX,c+16(FP)RET主函数1.gopackagemainfuncadd(a,bint)intfuncmain()......