在golang中如何正确判断接口是否为nil
本文主要来分析一下在golang中,如何判断interface是否为nil,以及相关注意事项。
正常情况下,我们声明一个interface类型的变量,默认值将会返回nil,以golang自带的io.Writer为例
var writer io.Writer
fmt.Printf("writer is nil => %t\n", writer == nil)

当然我们也可以用具体的实现结构来定义一个指针变量,它的默认值也是nil
var bufWriter *bufio.Writer
fmt.Printf("bufWriter is nil => %t\n", bufWriter == nil)
输出结果与上述的一样

以上的输出都是我们预期中的结果。
在实际开发中我们经常会碰到从某个函数中返回interface实例的情况,例如
bufWriter := func() io.Writer {
var w *bufio.Writer
fmt.Printf("w is nil => %t\n", w == nil)
return w
}()
fmt.Printf("bufWriter is nil => %t\n", bufWriter == nil)
此时我们的返回值是否仍旧与预期中的一致呢?

结果好像跟我们预想的有一些不太一样,因为在匿名函数中返回的是一个定义但是还未赋值的指针类型,并且在函数内部判断时,已经输出该变量为nil了,但是当我们在外部接收到这个值的时候,似乎变成非nil状态了
看着好像有一些诡异
那么,让我们来实际调用一下这个接口的函数试试
bufWriter := func() io.Writer {
var w *bufio.Writer
fmt.Printf("w is nil => %t\n", w == nil)
return w
}()
if bufWriter != nil {
bufWriter.Write([]byte("golang"))
}
可以看到,我们明明已经进行非空判断了,结果还是panic了

这是怎么回事呢?
其实当我们使用==直接将一个interface与nil进行比较的时候,golang会对interface的类型和值分别进行判断。
如果两者都为nil,在与nil直接比较时才会返回true,否则直接返回false。所以上面代码中interface与nil进行比较时返回的是false,因为此时interface变量的值是nil,但是他的类型不是nil,已经有了明确的实现类型,即bufio.Writer。因而当我们调用这个interface的函数成员时,就会直接panic。
所以在实际开发中,当interface类型的返回值已经明确为nil时,应该直接返回nil,而不是具体实现结构的未赋值空指针
bufWriter := func() io.Writer {
var w *bufio.Writer
if w == nil {
return nil
}
return w
}()
if bufWriter != nil {
bufWriter.Write([]byte("golang"))
} else {
fmt.Println("bufWriter is nil")
}
可以看到,此时我们可以正确判断interface是否为nil了

那么有没有办法去判断interface的真实值是否为nil呢?
当然可以,答案就是使用反射,示例如下:
bufWriter := func() io.Writer {
var w *bufio.Writer
fmt.Printf("w is nil => %t\n", w == nil)
return w
}()
fmt.Printf("bufWriter is nil => %t\n", bufWriter == nil)
fmt.Printf("IsNil => bufWriter is nil => %t\n", reflect.ValueOf(bufWriter).IsNil())
可以看到,当我们通过反射来判断是否为nil时,获取到了与我们预期一样的结果

参考资料
Why is my nil error value not equal to nil?
在golang中如何正确判断接口是否为nil的更多相关文章
- Golang中如何正确的使用sarama包操作Kafka?
Golang中如何正确的使用sarama包操作Kafka? 一.背景 在一些业务系统中,模块之间通过引入Kafka解藕,拿IM举例(图来源): 用户A给B发送消息,msg_gateway收到消息后,投 ...
- 在Golang中如何正确地使用database/sql包访问数据库
本文记录了我在实际工作中关于数据库操作上一些小经验,也是新手入门golang时我认为一定会碰到问题,没有什么高大上的东西,所以希望能抛砖引玉,也算是对这个问题的一次总结. 其实我也是一个新手,机缘巧合 ...
- Java中使用JSONTokener判断接口返回字符串是JSONObject还是JSONArray
今天在接口对接中,遇到一个问题,对方接口返回的JSONString,类型不确定,所以需要先做判断再进行处理.查阅资料后使用JSONTokener可进行处理,特此记录. String ret = ord ...
- golang中的类和接口的使用
类使用:实现一个people中有一个sayhi的方法调用功能,代码如下: type People struct { //.. } func (p *People) SayHi() { fmt.Prin ...
- 六、golang中的结构体和方法、接口
结构体: 1.用来自定义复杂数据结构 2.struct里面可以包含多个字段(属性) 3.struct类型可以定义方法,注意和函数的区分 4.strucr类型是值类型 5.struct类型可以嵌套 6. ...
- golang中的接口实现(一)
golang中的接口实现 // 定义一个接口 type People interface { getAge() int // 定义抽象方法1 getName() string // 定义抽象方法2 } ...
- golang中接口interface和struct结构类的分析
再golang中,我们要充分理解interface和struct这两种数据类型.为此,我们需要优先理解type的作用. type是golang语言中定义数据类型的唯一关键字.对于type中的匿名成员和 ...
- 七、golang中接口、反射
一.接口定义 1.定义 interface类型可以定义一组方法,但是这些不需要实现,并且interface不能包含任何变量 package main import ( "fmt" ...
- Golang 中的 面向对象: 方法, 类, 方法继承, 接口, 多态的简单描述与实现
前言: Golang 相似与C语言, 基础语法与C基本一致,除了广受争议的 左花括号 必须与代码同行的问题, 别的基本差不多; 学会了C, 基本上万变不离其宗, 现在的高级语言身上都能看到C的影子; ...
- golang中判断两个slice是否相等
在golang中我们可以轻松地通过==来判断两个数组(array)是否相等,但遗憾的是slice并没有相关的运算符,当需要判断两个slice是否相等时我们只能另寻捷径了. slice相等的定义 我们选 ...
随机推荐
- ubuntu 20.04 修改静态IP和dhcp自动分配IP
一.静态分配固定IP kuaibang@k8smaster:~$ sudo nano /etc/netplan/00-installer-config.yaml # This is the netwo ...
- js对象中的set和get方法
在js中,每个对象都有set和get方法,也可以自己进行定义,这里先简单说下用法 var person = { _name:'小花', get name() { return this._name + ...
- js 比较两个数组对象,取不同的值
let array1 = [ {'Num': 'A ', 'Name': 't1 '}, {'Num': 'B', 'Name': 't2'}, {'Num': 'C ', 'Name': 't3 ' ...
- Mysql学习:1、mysql安装及配置及连接Navicat
1.下载地址: https://dev.mysql.com/downloads/windows/installer/8.0.html 2.安装流程: a.选自定义安装:custom. b. 在下一步的 ...
- 20202411 2020-2021-2 《Python程序设计》实验二报告
20202411 2020-2021-2 <Python程序设计>实验二报告 课程:<Python程序设计> 班级: 2024 姓名: 陈书桓 学号:20202411 实验教师 ...
- qt中的一些对话框(个人备忘录)
一.标准对话框 1.对于颜色对话框 void MyWidget::on_pushButton_clicked() { QColorDialog dialog(Qt::red,this); dialog ...
- vue 3.0 引入swiper 8 direction不生效
需要手动给元素高度 <swiper class="my-swiper" :modules="modules" ...
- base64格式上传图片方法
function dataURItoBlob(dataURI) { const byteString = atob(dataURI.split(',')[1]); const mimeString = ...
- play() failed because the user didn‘t interact with the document first
使用js调用音频文件报错,错误信息如下:play() failed because the user didn't interact with the document first该报错是浏览器对于自 ...
- Spring 核心容器 IOC
目录 1. BeanFactory 2. BeanDefinition 3. BeanDefinitionReader 4 . Web IOC 容器初体验 一 .BeanFactory Spring ...