go语言nil有哪些特性
各位小伙伴们,大家好呀!看看今天我又给各位带来了什么文章?本文标题是《go语言nil有哪些特性》,很明显是关于Golang的文章哈哈哈,其中内容主要会涉及到nil、go语言等等,如果能帮到你,觉得很不错的话,欢迎各位多多点评和分享!
本文小编为大家详细介绍“go语言nil有哪些特性”,内容详细,步骤清晰,细节处理妥当,希望这篇“go语言nil有哪些特性”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
nil是Go语言中一个预定义好的标识符,表示空值或零值。在Go语言中,布尔类型的零值(初始值)为 false,数值类型的零值为0,字符串类型的零值为空字符串“''”,而指针、切片、映射、通道、函数和接口的零值则是nil。nil不是关键字或保留字,不同类型nil的指针是一样的,不同类型的nil是不能比较的,相同类型的nil值也可能无法比较。
nil是什么
在Go语言中,布尔类型的零值(初始值)为 false,数值类型的零值为 0,字符串类型的零值为空字符串"",而指针、切片、映射、通道、函数和接口的零值则是 nil。
nil 是Go语言中一个预定义好的标识符,有过其他编程语言开发经验的开发者也许会把 nil 看作其他语言中的 null(NULL),其实这并不是完全正确的,因为Go语言中的 nil 和其他语言中的 null 有很多不同点。
Go语言nil特性
nil 标识符是不能比较的
nil 不是关键字或保留字
不同类型 nil 的指针是一样的
不同类型的 nil 是不能比较的
两个相同类型的 nil 值也可能无法比较
nil 是常见引用类型的零值
相信写过Golang的程序员对下面一段代码是非常非常熟悉的了:
if err != nil { // do something.... }
当出现不等于nil
的时候,说明出现某些错误了,需要我们对这个错误进行一些处理,而如果等于nil
说明运行正常。那什么是nil
呢?查一下词典可以知道,nil
的意思是无,或者是零值。零值,zero value,是不是有点熟悉?在Go语言中,如果你声明了一个变量但是没有对它进行赋值操作,那么这个变量就会有一个类型的默认零值。这是每种类型对应的零值:
bool -> false numbers -> 0 string -> "" pointers -> nil slices -> nil maps -> nil channels -> nil functions -> nil interfaces -> nil
举个例子,当你定义了一个struct:
type Person struct { AgeYears int Name string Friends []Person } var p Person // Person{0, "", nil}
变量p
只声明但没有赋值,所以p的所有字段都有对应的零值。那么,这个nil
到底是什么呢?Go的文档中说到,nil是预定义的标识符,代表指针、通道、函数、接口、映射或切片的零值,也就是预定义好的一个变量:
type Type int var nil Type
是不是有点惊讶?nil
并不是Go的关键字之一,你甚至可以自己去改变nil
的值:
var nil = errors.New("hi")
这样是完全可以编译得过的,但是最好不要这样子去做。
nil有什么用
在了解了什么是nil
之后,再来说说nil
有什么用。
pointers
var p *int p == nil // true *p // panic: invalid memory address or nil pointer dereference
指针表示指向内存的地址,如果对为nil的指针进行解引用的话就会导致panic。那么为nil
的指针有什么用呢?先来看一个计算二叉树和的例子:
type tree struct { v int l *tree r *tree } // first solution func (t *tree) Sum() int { sum := t.v if t.l != nil { sum += t.l.Sum() } if t.r != nil { sum += t.r.Sum() } return sum }
上面的代码有两个问题,一个是代码重复:
if v != nil { v.m() }
另一个是当t
是nil
的时候会panic:
var t *tree sum := t.Sum() // panic: invalid memory address or nil pointer dereference
怎么解决上面的问题?我们先来看看一个指针接收器的例子:
type person struct {} func sayHi(p *person) { fmt.Println("hi") } func (p *person) sayHi() { fmt.Println("hi") } var p *person p.sayHi() // hi
对于指针对象的方法来说,就算指针的值为nil
也是可以调用的,基于此,我们可以对刚刚计算二叉树和的例子进行一下改造:
func(t *tree) Sum() int { if t == nil { return 0 } return t.v + t.l.Sum() + t.r.Sum() }
跟刚才的代码一对比是不是简洁了很多?对于nil
指针,只需要在方法前面判断一下就ok了,无需重复判断。换成打印二叉树的值或者查找二叉树的某个值都是一样的:
func(t *tree) String() string { if t == nil { return "" } return fmt.Sprint(t.l, t.v, t.r) } // nil receivers are useful: Find func (t *tree) Find(v int) bool { if t == nil { return false } return t.v == v || t.l.Find(v) || t.r.Find(v) }
所以如果不是很需要的话,不要用NewX()去初始化值,而是使用它们的默认值。
slices
// nil slices var s []slice len(s) // 0 cap(s) // 0 for range s // iterates zero times s[i] // panic: index out of range
一个为nil
的slice,除了不能索引外,其他的操作都是可以的,当你需要填充值的时候可以使用append
函数,slice会自动进行扩充。那么为nil
的slice的底层结构是怎样的呢?根据官方的文档,slice有三个元素,分别是长度、容量、指向数组的指针:
当有元素的时候:
所以我们并不需要担心slice的大小,使用append的话slice会自动扩容。(视频中说slice自动扩容速度很快,不必担心性能问题,这个值得商榷,在确定slice大小的情况只进行一次内存分配总是好的)
map
对于Go来说,map,function,channel都是特殊的指针,指向各自特定的实现,这个我们暂时可以不用管。
// nil maps var m map[t]u len(m) // 0 for range m // iterates zero times v, ok := m[i] // zero(u), false m[i] = x // panic: assignment to entry in nil map
对于nil
的map,我们可以简单把它看成是一个只读的map,不能进行写操作,否则就会panic。那么nil
的map有什么用呢?看一下这个例子:
func NewGet(url string, headers map[string]string) (*http.Request, error) { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, err } for k, v := range headers { req.Header.Set(k, v) } return req, nil }
对于NewGet
来说,我们需要传入一个类型为map的参数,并且这个函数只是对这个参数进行读取,我们可以传入一个非空的值:
NewGet("http://google.com", map[string]string{ "USER_AGENT": "golang/gopher", },)
或者这样传:
NewGet("http://google.com", map[string]string{})
但是前面也说了,map的零值是nil
,所以当header
为空的时候,我们也可以直接传入一个nil
:
NewGet("http://google.com", nil)
是不是简洁很多?所以,把nil
map作为一个只读的空的map进行读取吧。
channel
// nil channels var c chan t <p>关闭一个<code>nil</code>的channel会导致程序<code>panic</code>(如何关闭channel可以看这篇文章:如何优雅地关闭Go channel)举个例子,假如现在有两个channel负责输入,一个channel负责汇总,简单的实现代码:</p><pre class="brush:js;toolbar:false;">func merge(out chan<p>如果在外部调用中关闭了a或者b,那么就会不断地从a或者b中读出0,这和我们想要的不一样,我们想关闭a和b后就停止汇总了,修改一下代码:</p><pre class="brush:js;toolbar:false;">func merge(out chan<p>在知道channel关闭后,将channel的值设为nil,这样子就相当于将这个select case子句停用了,因为<code>nil</code>的channel是永远阻塞的。</p><p><strong>interface</strong></p><p>interface并不是一个指针,它的底层实现由两部分组成,一个是类型,一个值,也就是类似于:(Type, Value)。只有当类型和值都是<code>nil</code>的时候,才等于<code>nil</code>。看看下面的代码:</p><pre class="brush:js;toolbar:false;">func do() error { // error(*doError, nil) var err *doError return err // nil of type *doError } func main() { err := do() fmt.Println(err == nil) }
输出结果是false
。do
函数声明了一个*doErro
的变量err
,然后返回,返回值是error
接口,但是这个时候的Type已经变成了:(*doError,nil),所以和nil
肯定是不会相等的。所以我们在写函数的时候,不要声明具体的error变量,而是应该直接返回nil
:
func do() error { return nil }
再来看看这个例子:
func do() *doError { // nil of type *doError return nil } func wrapDo() error { // error (*doError, nil) return do() // nil of type *doError } func main() { err := wrapDo() // error (*doError, nil) fmt.Println(err == nil) // false }
这里最终的输出结果也是false
。为什么呢?尽管wrapDo
函数返回的是error
类型,但是do
返回的却是*doError
类型,也就是变成了(*doError,nil),自然也就和nil
不相等了。因此,不要返回具体的错误类型。遵从这两条建议,才可以放心地使用if x != nil
。
读到这里,这篇“go语言nil有哪些特性”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注golang学习网行业资讯频道。
今天带大家了解了nil、go语言的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

- 上一篇
- Go语言中延迟执行语句是哪个

- 下一篇
- Go语言包如何使用
-
- 等待的棒棒糖
- 这篇技术贴真及时,太细致了,很好,码起来,关注博主了!希望博主能多写Golang相关的文章。
- 2023-06-19 04:03:54
-
- Golang · Go教程 | 19小时前 |
- TigervncDebian多用户共享桌面超简单教程
- 482浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Go语言新手必看!切片vs数组,一次搞定这两个核心知识点
- 472浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Docker在Debian上运行超简单教程(保姆级教学)
- 210浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Debian设置hostname踩坑记录:权限问题大揭秘
- 334浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Debian装SQLServer?这些问题你一定要注意!
- 284浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Debian系统下Jenkins自动化部署脚本教学
- 367浏览 收藏
-
- Golang · Go教程 | 2天前 |
- DebianSwap服务器应用实测,这些场景真的用得上!
- 319浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Debian跑TigerVNC实测!真香警告,快来看看性能咋样~
- 171浏览 收藏
-
- Golang · Go教程 | 2天前 |
- 在Debian上玩转SQLServer备份还原,手把手教你一步步操作
- 498浏览 收藏
-
- Golang · Go教程 | 2天前 |
- DebianOverlay不会玩?手把手教你轻松定制化安装
- 258浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Go语言实战:time.Ticker&time.After用法区别及避坑技巧
- 240浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Debian系统如何快速定位&干掉那些讨厌的僵尸进程
- 317浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 茅茅虫AIGC检测
- 茅茅虫AIGC检测,湖南茅茅虫科技有限公司倾力打造,运用NLP技术精准识别AI生成文本,提供论文、专著等学术文本的AIGC检测服务。支持多种格式,生成可视化报告,保障您的学术诚信和内容质量。
- 19次使用
-
- 赛林匹克平台(Challympics)
- 探索赛林匹克平台Challympics,一个聚焦人工智能、算力算法、量子计算等前沿技术的赛事聚合平台。连接产学研用,助力科技创新与产业升级。
- 50次使用
-
- 笔格AIPPT
- SEO 笔格AIPPT是135编辑器推出的AI智能PPT制作平台,依托DeepSeek大模型,实现智能大纲生成、一键PPT生成、AI文字优化、图像生成等功能。免费试用,提升PPT制作效率,适用于商务演示、教育培训等多种场景。
- 58次使用
-
- 稿定PPT
- 告别PPT制作难题!稿定PPT提供海量模板、AI智能生成、在线协作,助您轻松制作专业演示文稿。职场办公、教育学习、企业服务全覆盖,降本增效,释放创意!
- 53次使用
-
- Suno苏诺中文版
- 探索Suno苏诺中文版,一款颠覆传统音乐创作的AI平台。无需专业技能,轻松创作个性化音乐。智能词曲生成、风格迁移、海量音效,释放您的音乐灵感!
- 57次使用
-
- Go疑难杂症讲解之为什么nil不等于nil
- 2022-12-22 374浏览
-
- golang中的nil接收器详解
- 2023-01-07 355浏览
-
- 有关Go语言拼接URL路径的方法
- 2023-03-09 185浏览
-
- go语言能不能做后端
- 2023-03-03 460浏览
-
- go语言和java的区别是什么
- 2023-03-03 430浏览