大家好,我是明哥。在开始之前,先问大家一个很像Go的经典问题:如何判断一个interface{}的值是否为nil?这也是面试中可能会问到的问题。这道题很“入迷”,没有特别细心的朋友,很容易就切到这里了。相信很多人都会下意识的回答,直接用v==nil判断不是很好吗?很久以前我也是这么想的,但是写了个demo之后才发现,事情并没有那么简单。请看下面的代码,你可以先猜猜输出的结果。packagemainimport("fmt")funcmain(){vara*string=nilvarbinterface{}=afmt.Println(b==nil)}答案应该和你潜意识的答案相反。输出结果是false,为什么?接下来,我们将谈谈它的内部。1、两个接口的比较接口内部实现包含两个字段,一个是type,一个是data。对于这样一个变量varageinterface{}=25,内部结构是这样的,两个接口的比较必然是这两个字段不同。关系。经验证,只有在以下两种情况下,这两个接口才会相等。在第一种情况下,类型和数据都是相等的。在下面的代码中,p1和p2的类型都是Profile,data是{"iswbm"},所以p1和p2是相等的,而p3和p3都是*Profile,但是由于data存放的是结构体的地址,而两个地址之和不一样,p3和p4不相等,p4ProfileInt=&Profile{"iswbm"},&Profile{"iswbm"}fmt.Printf("p1-->type:%T,data:%v\n",p1,p1)fmt.Printf("p2-->type:%T,data:%v\n",p2,p2)fmt.Println(p1==p2)//truefmt.Printf("p3-->type:%T,data:%p\n",p3,p3)fmt.Printf("p4-->type:%T,data:%p\n",p4,p4)fmt.Println(p3==p4)//false}运行后输出为如下p1-->type:main.Profile,data:{iswbm}p2-->type:main.Profile,data:{iswbm}truep3-->type:*main.Profile,data:0xc00008e200p4-->type:*main.Profile,data:0xc00008e210false第二种特殊情况:两个接口都是nil。当接口的类型和数据都处于未设置状态时,接口类型和所有值都是nilpackagemainimport"fmt"funcmain(){varp1,p2interface{}fmt.Println(p1==p2)//truefmt.Println(p1==nil)//true2。接口和非接口比较接口和非接口比较时,非接口会转换成接口,然后按照比较两个接口的规则进行比较。例子如下:packagemainimport("fmt""reflect")funcmain(){varastring="iswbm"varbinterface{}="iswbm"fmt.Println(a==b)//true}上面的例子可能很简单要理解的话请看下面的例子(文章开头的例子),为什么b不等于nil?packagemainimport("fmt")funcmain(){vara*string=nilvarbinterface{}=afmt.Println(b==nil)//false}但是当你用b==nil判断的时候,右边的nil是不是简单的我们理解的nil,正确的理解应该是类型是nil,值也是nil。Go会先把nil转成interface(type=nil,data=nil),和b(type=*string,data=nil)一样,data虽然一样,但是type不相等,所以不相等.有没有办法判断一个interface{}是否为nil?有办法,不过是借助反射,不到万不得已用反射包。packagemainimport("fmt""reflect")funcIsNil(iinterface{})bool{vi:=reflect.ValueOf(i)ifvi.Kind()==reflect.Ptr{returnvi.I??sNil()}returnfalse}funcmain(){vara*string=nilvarbinterface{}=afmt.Println(IsNil(b))}本文通过一些例子对比介绍了Go内部的一些实现原理。对于很多人来说,这可能是一种“新”知识。以后在coding过程中肯定给自己挖一个“大坑”,而这门语言里面的“坑”,不知道就是不知道,也很难找无论您如何检查代码。希望通过这篇文章,带你填好这个“坑”。本文原属于围棋面试题库专栏系列。以前在题目上明明说是面试题。考虑到最近有些人没有面试,怕是你不面试也会错过这种必须掌握的知识。内容可以不在标题上特别标注为面试题。本专栏的所有文章我都发布在了Github上:https://github.com/iswbm/golang-interview这个账号没有留言功能。如果文章有什么不对的地方,可以去那里提交issue帮我改正。对了,能不能指点一下??,我整理题库的地方,方便索引查找。加油,下次见!
