interface{}与nil,违背了==的传递性
程序:
func main() {
var t *T
var i interface{} = t
fmt.Println(t == nil, i == t, i == nil)
}
结果:true true false
t,i,nil三者间只有两个==成立,我知道原因是interface{}两个成员造成。但这样一个违背常识的语义特征就这么永远保持下去吗?
程序:
func main() {
var t *T
var i interface{} = t
fmt.Println(t == nil, i == t, i == nil)
}
结果:true true false
t,i,nil三者间只有两个==成立,我知道原因是interface{}两个成员造成。但这样一个违背常识的语义特征就这么永远保持下去吗?
共 23 个回复
stevewang
说到常识,我也很想知道为什么C里0.00003不等于0.00003,为什么这样一个违背常识的语义特征要在C里永远保持下去。
snake117
nil接口和保管nil值的接口当然是两回事
stevewang
C++也违反了==传递性的常识。。。
dayn9
浮点数的问题,目前在不牺牲性能的情况下绝无解决可能,是硬缺陷,而这里探讨的是语言设计的软问题,无可比性。楼上情况到有相似性,不过b == c毕竟不能比,其提示作用要鲜明得多。退一步说,假设两者便斤八两,但拿世界上坑最多的语言来佐证另一个语言的坑的合理性,恐怕欠说服力。
我也并非不知道是怎么回事,只是困惑于是不是有更好的解决方案。
stevewang
每种语言都有自己的惯用法,仅此而已。 go是工程语言,致力于解决实际问题,而不是去追求形式上的完美。这是我的理解。
ThoseFlowers
nil一词多义
第一个nil表示空指针,第二个nil表示没有“挂上东西”的接口
第一个比较式是判断t是否为空指针,第二个比较式是判断这个接口是否没“挂上东西”
Bluek404
这个和指针有关吧 如果这样写:
ggaaooppeenngg
我试了一下,我觉得@Bluek404 说的是对的.
ggaaooppeenngg
还有 @ThoseFlowers 的说法也很有道理,如果挂上的是空的interface,也是nil,但是挂上了指针是有值的,虽然指针是空的。
stevewang
楼主不是不知道原因,他是不喜欢这种设计。
se7enday
http://my.oschina.net/goal/blog/194233 这个说的很详细
Bluek404
我觉得这么设计也是有原因的
比如:
按理说这两个都应该等于nil的
但是如果都等于nil的话,那么a就==b了
但是a和b是明显不等于的
因为a里面存储的是nil,但是b是一个指向nil的指针
然后看楼主的程序:
当
var t *T
的时候interface{}里储存的是指向t的指针,然后判断interface{}是否等于t是看指针指向的值是多少,而判断是否等于nil是判断的interface{}本身是否是nil而当
var t T
的时候interface{}里储存的是t里面值的copy就是nil,所以interface{}就等于nil要改变这个也很简单,和Golang的团队说一下,让他们把所有内容为指针的变量默认输出指针,而不是指针指向的内容,然后再加一个方法专门从指针提取指向的内容
不过这样写程序就太麻烦了,所以这点抽象还是有必要的
以上仅属个人见解,最好还是去官方邮件列表提问
snake117
@dayn9 @Bluek404
这个程序只返回 "x==nil"。
所以,你可以明确的知道,nil接口和装入nil的接口完全不是一回事。
应该说,如果是一回事才有问题。比如某个方法,出于一致性需要返回一个接口,那么返回nil接口和返回装入nil的接口,其意义是完全不同的。
Bluek404
@snake117 难道不是因为interface{} 里装的是一个nil指针?
snake117
@Bluek404 是啊。
我的意思是,不把nil接口和装入nil的接口等同有其意义,从各种方面来说,都不应该让它们等同。
Bluek404
@snake117 QQ群上一位朋友给出的方法
输出:
Bluek404
啊对了补充一下16楼 http://golanghome.com/post/324
David
主要的歧义在于
nil
,这样写是三个true
的 (http://play.golang.org/p/2sJNi6Ad0n)但是编译器看到
i == nil
的时候,只能够把无类型的nil
看成是interface{}
的nil
,也就是==
检查的是interface{}
里的类型是空(此时应该不检查 value 的,因为interface{}
如果没有类型,取值无意义)没有想到更好的设计能解决这个问题,而且只为了满足
==
的传递性没有啥实用性。sisyphsu
特意注册账号来发表一下意见。
最近我深深地踩了这个坑,并且在Google上见到不计其数的人,都在询问interface{}为什么不等于nil。在golang的Github ISSUE里面也见到许多类似的问题。
楼上拿“浮点数比较”与“接口类型比较”来反驳讽刺楼主,明显是错误的,因为问题的关键是“判空”,而不是判断类型,也不是判断误差。
Golang是一个非常优秀的语言,鄙人以前长期从事java、c++开发,过渡过来非常流畅。
但是就事论事,interface{}判nil的设计,实在是太愚蠢了。与数十年来、各种语言通用的“判空”设计,完完全全地冲突了。我相信大部分人,使用Golang进行开发时候,早晚会在这个坑上面,重重地摔一跤。
借路描述一下这个坑:
java里面你可能这样判断null
interfaceA != null
c++里面你可能这样判断null
baseClassPTR != nullptr
但是在Golang里面你这样做就有可能panic、crash
interfaceA != nil
你应该这样判断interface为nil:
interfaceA != nil && !reflect.ValueOf(interfaceA).IsNil()
假以时日,如果Golang在国内广泛使用之后,我敢断定“interface判nil”必然成为面试必考题。
topuk
也是特意注册账号来回答,不过我只想指出第一个回复 @stevewang 的错误之处:
f3 == 0.00003当然不可能正确,在C/C++中,浮点数的字面值类型默认是double类型,你用一个float类型去比较,会相等?
这不是违背常识的语义特征,而是你压根没弄明白。
topuk
还有下面的代码
我真的不是不友善,这代码什么玩意?C++代码引入C的IO头文件(我知道这是兼容的),用printf去输出,然后a==b,这比较的是指针,我想问,你知道你自己这段代码是在表达什么吗?你能弄清楚对象及其指针,以及构造和运算符重载是什么吗?
flym03
一看好多c基础都不扎实
wuming
简直无力吐槽!
看看这段代码,a b c d 均为 nil,那按照你的逻辑 a b c d应该都相等了吧。可是a==b根本编译不过,那岂不是golang编译器有问题?
golang引用类型包括:pointer, slice,chan,map等。他们的默认零值均为nil