本文主要来分析一下在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的更多相关文章

  1. Golang中如何正确的使用sarama包操作Kafka?

    Golang中如何正确的使用sarama包操作Kafka? 一.背景 在一些业务系统中,模块之间通过引入Kafka解藕,拿IM举例(图来源): 用户A给B发送消息,msg_gateway收到消息后,投 ...

  2. 在Golang中如何正确地使用database/sql包访问数据库

    本文记录了我在实际工作中关于数据库操作上一些小经验,也是新手入门golang时我认为一定会碰到问题,没有什么高大上的东西,所以希望能抛砖引玉,也算是对这个问题的一次总结. 其实我也是一个新手,机缘巧合 ...

  3. Java中使用JSONTokener判断接口返回字符串是JSONObject还是JSONArray

    今天在接口对接中,遇到一个问题,对方接口返回的JSONString,类型不确定,所以需要先做判断再进行处理.查阅资料后使用JSONTokener可进行处理,特此记录. String ret = ord ...

  4. golang中的类和接口的使用

    类使用:实现一个people中有一个sayhi的方法调用功能,代码如下: type People struct { //.. } func (p *People) SayHi() { fmt.Prin ...

  5. 六、golang中的结构体和方法、接口

    结构体: 1.用来自定义复杂数据结构 2.struct里面可以包含多个字段(属性) 3.struct类型可以定义方法,注意和函数的区分 4.strucr类型是值类型 5.struct类型可以嵌套 6. ...

  6. golang中的接口实现(一)

    golang中的接口实现 // 定义一个接口 type People interface { getAge() int // 定义抽象方法1 getName() string // 定义抽象方法2 } ...

  7. golang中接口interface和struct结构类的分析

    再golang中,我们要充分理解interface和struct这两种数据类型.为此,我们需要优先理解type的作用. type是golang语言中定义数据类型的唯一关键字.对于type中的匿名成员和 ...

  8. 七、golang中接口、反射

    一.接口定义 1.定义 interface类型可以定义一组方法,但是这些不需要实现,并且interface不能包含任何变量 package main import ( "fmt" ...

  9. Golang 中的 面向对象: 方法, 类, 方法继承, 接口, 多态的简单描述与实现

    前言: Golang 相似与C语言, 基础语法与C基本一致,除了广受争议的 左花括号 必须与代码同行的问题, 别的基本差不多; 学会了C, 基本上万变不离其宗, 现在的高级语言身上都能看到C的影子; ...

  10. golang中判断两个slice是否相等

    在golang中我们可以轻松地通过==来判断两个数组(array)是否相等,但遗憾的是slice并没有相关的运算符,当需要判断两个slice是否相等时我们只能另寻捷径了. slice相等的定义 我们选 ...

随机推荐

  1. react 学习笔记更新2.0

    1.性能优化 1.shouldComponentUpdate 在render调用之前会调用shouldComponentUpdate,不建议在 shouldComponentUpdate() 中进行深 ...

  2. Linux基础第六章:逻辑卷的使用、扩容和磁盘配额

    一.逻辑卷的使用及扩容 1.概念优点及注意事项 2.使用命令及基本格式 3.创建逻辑卷 ①创建物理卷 ②创建卷组 ③创建逻辑卷 ④格式化.挂载yk26逻辑卷在/mnt下并在逻辑卷yk26下创建文件a. ...

  3. vue3+ts获取dom元素高度

    vue3+ts获取dom元素高度 <template> <div class="digestDetail-indedx"> <div class=&q ...

  4. Java-ArrayList常用API

    返回值 方法 用途 boolean add(E e) 将指定的元素追加到此列表的末尾. void add(int index, E element) 在此列表中的指定位置插入指定的元素. boolea ...

  5. Peer Review

    What are Peng (Bob) Chi's top 3 strengths?  Can you give an example of how one or two of those stren ...

  6. noi 1.1 2 输出第二个整数

    描述 输入三个整数,把第二个输入的整数输出. 输入 只有一行,共三个整数,整数之间由一个空格分隔.整数是32位有符号整数. 输出 只有一行,一个整数,即输入的第二个整数. 样例输入 123 456 7 ...

  7. linux 基础命令 apt

    Linux apt 命令 apt(Advanced Packaging Tool)是一个在 Debian 和 Ubuntu 中的 Shell 前端软件包管理器. apt 命令提供了查找.安装.升级.删 ...

  8. a标签做锚点定位,有部分内容被置顶头部遮挡的解决方法

    被遮挡的元素添加如下样式: /**这里假定头部高度是100px*/ position: relative;top: 100px;/**关键样式如下,我这里上面有加定位,如果没用定位,下面的数值需根据实 ...

  9. 微信小程序:流程/步骤流/时间轴自定义组件

    效果图: 1.首先在小程序components目录下新建一个名为step的文件夹,再建step组件名.结构如下. 直接上代码 step.wxml <view class="step&q ...

  10. Java基础Day5-数组

    一.数组声明创建 首先必须声明数组变量,才能在程序中使用数组. 声明数组变量的语法如下: dataType[] arrayRefVar; 例如: int[] nums; Java语言使用new操作符来 ...