为什么Kotlin为什么将==用于结构相等并引入===用于引用相等

时间:2019-03-19 21:29:22

标签: java kotlin reference equality structural-equality

通常,Kotlin中的每个设计决策都感觉很不错,并且可以很好地过渡到Java。作为Java开发人员,您可以开始将其中的Kotlin视为具有更少样板的更简洁的Java进行编码,然后平稳地过渡到函数式编程等更高级的方面。

但是我想知道的一件事是为什么其设计者决定使==的行为与equals相同,然后引入===进行参照相等性检查。我可以想像试图吸引其他Java开发人员参与其中,让他们看到您的Kotlin代码,然后思考:“哦,不,应该在等号调用的地方进行引用检查!”

离开这里的Java约定的思路是什么?为了清楚起见,我很清楚地了解了Kotlin中==equals===之间的区别,我只是想知道为什么。

2 个答案:

答案 0 :(得分:9)

主要原因可能是对象相等性比对象身份更受检查,因此它至少应该一样容易。

我还没有看到明确的声明。但是Kotlin In Action书中有一个Kotlin小组成员的指针。第4.3.1节介绍了==运算符,它首先描述了Java的比较,并指出:

  

在Java中,有一种经常调用equals的众所周知的做法,并且还有一个众所周知的忘记这样做的问题。

在Java中,检查对象身份很容易:

if (firstObj == secondObj)

但是检查对象是否相等的时间更长,而且不清楚:

if (firstObj.equals(secondObj))

-或者,如果您不想冒险遇到NullPointerException:

if ((firstObj == null) ? (secondObj == null) : firstObj.equals(secondObj))

您可以看到打字和纠正疼痛的痛苦程度。 (特别是当这些对象之一是带有副作用的表达式时……)

因此,很容易忘记它们之间的差异,或者不理会它们,而改用==。 (这很可能会导致细微,难以发现和间歇咬伤的错误。)

但是,Kotlin使最常见的操作变得更容易:它的==运算符使用equals()检查对象的相等性,并且还要进行空检查。这解决了Java的“忘记这样做的问题”。

(尽管与Java代码的互操作性显然是一个主要目标,但JetBrains并没有将自己局限于尝试像Java那样看起来。Kotlin尽可能从Java借用,但不惧怕改变情况变得更好。您可以看到,在使用valvar以及声明的尾随类型,作用域和开放性的默认值不同,方差的处理方式不同时,等等。)

Kotlin的动机之一就是解决Java中的许多问题。 (实际上,JetBrains的comparison语言是从列出“ Kotlin中解决的某些Java问题”开始的。)因此,这很可能是更改背后的主要原因。

答案 1 :(得分:3)

除了gidds的出色回答外,还有Java以外的其他语言对Kotlin产生了重大影响。特别是Scala和C#。 Dmitry Jemerov的引号(链接是指向InfoWorld的,我不太喜欢,但这是我找到的最好的来源):

  

我们已经研究了所有现有的JVM语言,但它们都不满足我们的需求。 Scala具有正确的功能,但最明显的不足是编译速度很慢。

显然==是他们认为Scala正确的那些功能之一,因为它的工作原理完全相同(直到引用相等的名称,在Scala中为eq)。

您可以在Scala编程一书中找到an explanation for Scala's design,该书的作者是马丁·奥德斯基(Martin Odersky):

  

如11.2节所述,Scala和Java中的相等定义不同。 Java有两个相等性比较:==运算符,它是值类型和引用类型的对象标识的自然相等性;而equals方法,是(用户定义)引用类型的规范相等性。这个约定是有问题的,因为更自然的符号==并不总是对应于自然的平等概念。使用Java进行编程时,对于初学者来说,常见的陷阱是在应该将对象与equals进行比较时将它们与==进行比较。例如,即使x和y具有相同顺序的完全相同的字符,使用“ x == y”比较两个字符串x和y在Java中也很可能产生false。

     

Scala还具有表示对象标识的相等方法,但是使用很少。如果x和y引用相同的对象,则这种写为“ x eq y”的等式成立。在Scala中,为每种类型的“自然”相等保留==相等。对于值类型,==是值比较,就像Java中一样。对于引用类型,==与Scala中的equals相同。您可以通过覆盖始终从类Any ...继承的equals方法来为新类型重新定义==的行为。

另一方面,C#允许==Equals分开重载var hash = HashCodeUtil.GetHashCode( poco.Field1, poco.Field2, ..., poco.FieldN); ,他们最终选择了一名语言设计师saying

  

长的答案是,整个事情很奇怪,而且都没有达到理想的效果。