本文主要来分析一下在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. MSSQL 查看数据库所有的触发器

    SELECT object_name(a.parent_obj) as [表名] ,a.name as [触发器名称] ,(case when b.is_disabled=0 then '启用' el ...

  2. <小李飞刀>系列 随笔

    1.多情剑客无情剑 古龙的作品在电视上只看过电影版的陆小凤传奇,对古龙的作品也没有过系统的了解,初读时听到了李寻欢的名字,突然感觉可惜.觉得如此早就读到这种级别的小说有些暴殄天物,不过也算是以白纸状态 ...

  3. HDFS Shell 操作

    HDFS Shell 操作 HDFS Shell 命令行格式 格式一:hadoop fs –命令名 参数 格式二:hdfs dfs –命令名 参数 HDFS 常用命令及参数 ls:查看 hdfs 中的 ...

  4. 训练题——ADC读取温度

    Author:XuanYu 利用ADC测量单片机内部温度 废话不多说,直接开搞. 科普 先科普一下ADC(不是 AD carry!),ADC是模数转化器,就是模拟信号转换成数字信号的东西,通常的模数转 ...

  5. Python基础数据类型-Number(数字)

    a = -1 # int b = 2.0 # float c = 13.11 # float d = 3.14j # complex print(type(a), type(b), type(c), ...

  6. c++学习 4 运算符及其应用技巧

    一 按位与运算符 "&"按位与运算符,全1为1,有0则0. 特点:和1相与保持不变,和0相与都变为0. 功能:将指定位置清0. example: 1000 1100 &am ...

  7. Java学习笔记2-1

    2.对象容器(1)   今天学习一下Java里面的一些容器的基本功能,今天先来Arraylist. 一.Arraylist   容器类主要是为了存放一些按某些方式排列的对象,arraylist是一种容 ...

  8. Component inside <Transition> renders non-element root node that cannot be animated

    原因是transition标签下存在多个根标签 原代码: 解决方法 Suspense还处于试验阶段,可能导致default内容与fallback内容同时存在,导致错误

  9. Visual Studio快速清除程序中的空行 删除空行

    Ctrl+H; 正则替换 ^(?([^\r\n])\s)*\r?$\r?\n 快速删除多个空行

  10. day28_常用模块——hashlib,logging模块

    hashlib(摘要算法) Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度 ...