你真的知道 GO 中 nil 代表什么吗?

本篇文章主要是来聊聊 Golang 中关于 nil 的使用方式及理解,看看有没有你还不知道的情况呢?

[图片上传失败...(image-7d6c6b-1695915565900)]

使用 Golang 的朋友都知道,在 Golang 的世界里面,有一个预先声明的标识符 nil

nil 标识符可以作为多种数据结构的零值,通常我们会将 nil 就认为是空的意思,就像 C 语言里面的 NULL 一样

此处说到零值,他其实就是一种数据类型还没有被初始化的时候的默认值,对应着的就是一个零值

例如:

整形的零值,是 0

字符串的零值是 ""

那么布尔类型的零值自然就是 false

零值默认为 nil 的数据结构可多了,有这些:

  • 函数
  • 指针
  • interface{}
  • Map
  • 切片 slice
  • 通道 channel

接下来分别从零值为 nil 的几种数据类型来聊聊的 nil 的那些事

nil 和 true/false 一样,不是 Golang 的关键字

nil 和 一般我们知道的布尔类型的值(true/false)类似,都不是 Golang 的关键字

我们可以将 nil,true,或者 false 作为变量的名字,并进行赋值和输出

func main() {
   log.SetFlags(log.Lshortfile)
   nil := 123
   true := 111
   false := 222
   log.Printf("nil == %+v,true == %+v,false==%+v", nil,true,false)
}

[图片上传失败...(image-df7066-1695915565900)]

自然,例如 const 是 Golang 中的关键字,我们就没有办法将 const 作为变量名

[图片上传失败...(image-f5c93c-1695915565900)]

nil 占用的空间因不同的数据结构而不同

在 C 语言中,我们知道可以通过 sizeof 去查看指针占用的空间,可能是 4 字节,也有可能是 8 字节,一般来说这是对应着 32 位系统和 64 位系统

例如一个空指针,也是会占用空间的,表示他是一个指针,指针的指向是 NULL

[图片上传失败...(image-c5cf05-1695915565900)]

那么对应到 Golang 中,以 nil 作为零值的数据结构,同样有自己所占用的空间,占用空间的大小也是不一样的,Golang 中可以使用 unsafe 包中的 Sizeof 方法来进行查看

func main() {
   log.SetFlags(log.Lshortfile)


   var ptr *int = nil
   log.Println("nil 指针:",unsafe.Sizeof(ptr))

   var in interface{} = nil
   log.Println("nil interface{}:",unsafe.Sizeof(in))

   var mp map[string]string = nil
   log.Println("nil map:",unsafe.Sizeof(mp))

   var sli []int = nil
   log.Println("nil slice:",unsafe.Sizeof(sli))

   var ch chan string = nil
   log.Println("nil channel:",unsafe.Sizeof(ch))

   var fun func() = nil
   log.Println("nil 函数:",unsafe.Sizeof(fun))

}

[图片上传失败...(image-89517b-1695915565900)]

此处可以看到,对于同一个系统,咱们指针的占用空间 C 语言和 Golang 是一样的(都是 8 字节),对于切片,map 等数据结构 nil 的大小,也与他们自身的底层数据结构有关,对于每一个数据结构的底层细节,可以看到文末的历史文章

切片零值 nil

我们知道,切片的底层数据结构是,一个指针 ptr,一个 cap 表示切片容量,一个 len 表示切片中已有数据的长度

[图片上传失败...(image-fb30d7-1695915565900)]

所以,看到这里,对于理解切片的 nil 为什么占用空间是 24 字节,就明白了吧

  • 一个指针占用 8 字节
  • 一个 cap int 类型,占用 8 字节
  • 一个 len int 类型,占用 8 字节

对于一个空切片,使用的时候,需要注意不能去取索引对应的值,因为对于一个空切片来说,根本不存在,若访问这一片内存,则会报panic: index out of range数组越界

我们对于一个 nil 的切片,可以去取地址,可以取长度,可以取容量,自然也是可以使用 append() 来追加数据的

使用 append 来追加数据就会涉及到扩容,此处就不过多赘述了,详情可以查看关于 slice 的原理介绍

map 零值 nil

对于 map 也是会存在同样的问题,我们去取 map 中的某一个节点的值的时候

如果 map 之前是经过初始化的,那么我们访问一个不存在的 key 是没有问题的,且我们一般去访问 map 中的值的时候会比较谨慎,例如:

func main() {
   log.SetFlags(log.Lshortfile)

   demoMap := map[int]string{
      1: "xiaoming",
      2: "xiaoxiong",
   }
   value, ok := demoMap[3]
   if ok{
      log.Printf("value == %+v",value)
   }else{
      log.Println("no exsit")
   }

   var demoMap2 map[int]string    // nil
   demoMap2[1] = "hhh"     // panic: assignment to entry in nil map

}

对于访问访问一个 nil 的 map ,不会出现问题,但是如果是去写入数据到某个节点上,那么就会出现panic: assignment to entry in nil map

[图片上传失败...(image-3c3a5e-1695915565900)]

Channel 通道零值 nil

对于通道 channel 零值 nil,我们就需要注意是从这个通道读取数据,还是将数据写入到这个通道中

从 nil 通道中读取数据

例如,若定义一个 channel ,var ch chan int

从 nil 通道中读取数据会阻塞: <- ch

[图片上传失败...(image-30bfbb-1695915565900)]

写入数据到 nil 通道

写入数据到 nil 通道会阻塞: ch<-1

[图片上传失败...(image-8046c1-1695915565900)]

关闭一个 nil 通道,会 panic , panic: close of nil channel

[图片上传失败...(image-60e863-1695915565900)]

当然,此处仅是聊聊关于 nil 涉及到的数据结构,以及简单的注意事项, 对于 channel 的原理和使用,可以查看文末的文章链接

指针零值 nil

对于指针的零值,我们应该是比较熟悉的了,如果你是从 C 语言转 Golang 的,那么这就更不在话下了

nil 的指针,异常点和前面说到的切片 slice 类似,当访问空指针上的值的时候,就会出现 panic

var ptr *int
log.Println(*ptr)
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x211f79]

[图片上传失败...(image-e84640-1695915565900)]

自然,仍然和切片类似,对于 nil 的指针,我们可以正常打印指针自己的地址,以及直接打印这个指针指向的值

var ptr *int
log.Println(&ptr)
log.Println(ptr)

[图片上传失败...(image-b548b-1695915565900)]

所以,一般在操作指针的时候,需要认真仔细,特别是对于新手使用指针,更要万分小心

但是一旦你熟悉了指针,你会爱上他的,由于 Golang 函数传参都是值传递

因此,我们一般开发的时候,会使用传指针的方式,虽然传递指针也是指针的拷贝,可是这样的资源开销会小很多

自然,对于指针和内存的内容,我们之后的文章再细聊

interface{} 零值 nil 和 函数零值 nil

函数零值 nil

对于函数的 nil,我们一般会使用在哪里呢?

例如我们传入的参数是一个函数的时候,具体的实现又需要这个函数去做业务,那么,这个时候我们传入了 nil,自然是会出问题的

func main() {
   testDemo(testFun)
   testDemo(nil)

}
func testFun(str string){
   fmt.Println("str == ",str)
}
func testDemo(fun func(string)){
   fun("hello")
}

[图片上传失败...(image-b628f2-1695915565900)]

所以,对于这种参数是函数的情况,咱们使用之前,需要去校验传入的函数是否是一个 nil,这已经是基本操作了

[图片上传失败...(image-bdb452-1695915565900)]

interface{} 零值 nil

interface{} 的零值,还记得占用多少字节吗?它占用的是 16 个字节

稍微了解 interface{} 的底层数据结构的就知道,他的底层是有一个 type 和一个data(无论是 iface 还是 eface),他俩都是指针,因此此处 nil 的 interface{} 占用 16 个字节

从此处,我们可以看到, interface{} 里面包含 2 个因素,只有当着俩因素都是 nil 的时候,整个 interface{} 才会是 nil

var in interface{}
var ptr  *int
if in == nil{
    // 此处的 in  类型是 nil ,值也是 nil ,因此会进来
}
in = ptr
if in == nil{
    // 此时的 in ,类型是 *int ,值是 nil ,因此不会进来
}

[图片上传失败...(image-51b900-1695915565900)]

[图片上传失败...(image-30a07d-1695915565900)]

有没有觉得还是挺有趣的呢,本次文章仅讨论关于 nil 的内容,其他的延伸内容可以查看文末的地址

看到这里,有没有对 nil 有了更多的认知了呢?希望能够对你有帮助

感谢阅读,欢迎交流,点个赞,关注一波 再走吧

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

[图片上传失败...(image-bfd19d-1695915565900)]

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

文中提到的技术点,感兴趣的可以查看这些文章:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容