15

在 的 scaladoc 中scala.Any,解释了运算符==(或方法==):

该表达式x == that等效于if (x eq null) that eq null else x.equals(that) http://www.scala-lang.org/api/current/#scala.Any

对于 的子类的对象AnyRef,我很容易理解,也没有看到什么奇怪的东西。

但是,对于 , 的值AnyVal(我的意思是Int, Double,Long等),上面的定义有些棘手(1 eq null?如果我们不转换1为 java.lang.Integer,这将无法编译)。而且,==行为方式也equals()不同。

我会举一些例子。

斯卡拉> 1 == 1
res0: 布尔 = 真

斯卡拉> 1 == 1.0
res1:布尔=真

斯卡拉> 1 == 1.2
res2: 布尔 = 假

scala> 2 == BigInt(2)
res3: 布尔 = 真

scala> 2.0 == BigInt(2)
res4:布尔=真

scala> 2 == BigInt(3)
res5: 布尔 = 假

到目前为止,没有什么奇怪的。但是如果我们用equals()方法做同样的事情,

scala> 1 等于 1
res7: 布尔 = 真

scala> 1 等于 1.0
res8: 布尔 = 假

scala> 1 等于 1.2
res9: 布尔 = 假

scala> 2 等于 BigInt(2)
res10: 布尔 = 假

scala> 2.0 等于 BigInt(2)
res11: 布尔 = 假

scala> 2 等于 BigInt(3)
res12: 布尔 = 假

因此,如果类型不同,equals() 总是返回 false,而 == 测试它们是否表示相同的值,如果它们被转换为相同的类型。

在子类的情况下AnyRef,方法==equals()返回相同。

scala> BigInt(2) == 2
res25: 布尔 = 真

scala> BigInt(2) == 2.0
res26:布尔=真

scala> BigInt(3) == 2
res27: 布尔 = 假

scala> BigInt(2) 等于 2
res28: 布尔 = 真

scala> BigInt(2) 等于 2.0
res29: 布尔 = 真

scala> BigInt(3) 等于 2
res30: 布尔 = 假

那么,为什么方法==equals()不同AnyVal呢?

我正在使用 Scala 版本 2.10.2(Java HotSpot(TM) 64 位服务器 VM,Java 1.7.0_25)。

编辑 1
我看到 == 不能被直接覆盖,因为它根据Programming in Scala, 2nd Edition被定义为 Any 类中的最终方法。

编辑 2
虽然有答案,但我的问题仍然存在。我将保留这个问题。与Java

相对应的是 Java 的原始类型和. 在 Java 中,and是类,所以它们的变量是引用,可以有. 这意味着,它们就像在 Scala 中一样。不是。 Scala 的-和不能有值,Java和. 此外, Java 中的 's用于引用相等(与Scala 中相同)。 你得到什么scala.Intscala.Longintlong
java.lang.Integerjava.lang.LongnullAnyRefAnyVal
AnyValscala.Intscala.Longnullintlong
java.lang.Integer==eq
java.lang.Integer在这方面,Scala REPL 中的 REPL 与您在带有 .java 源文件的纯 Java 项目中得到的完全不同。

但是,我可以从使用 Java 中的原始类型类得到的是:(这是 JAVA)

class Main {
    public static void main(String[] args) {
        System.out.println(String.valueOf(new java.lang.Integer(1).equals(1)));
        System.out.println(String.valueOf(new java.lang.Integer(1).equals(1L)));
        System.out.println(String.valueOf(new java.lang.Integer(1).equals(1.0)));
        System.out.println(String.valueOf(new java.lang.Integer(1).equals(new java.lang.Integer(1))));
        System.out.println(String.valueOf(new java.lang.Integer(1).equals(new java.lang.Long(1))));
    }
}

输出:

真的
错误的
错误的
真的
错误的
是的,它们的行为类似于 scala AnyVal 的equals()。但是,那么,为什么会发生这种情况呢?

Scala 的AnyVal's是否==对应于==Java 的原始类型
,Scala 的 AnyVal 是否equals()对应于equals()Java 的类类型?
BigInt 的相等性测试怎么样?Java 中没有对应的原始类型。
问题仍然...

编辑 3
我可以从 scaladoc 中找到一些信息。( http://www.scala-lang.org/api/current/index.html#scala.Int ) 我可以找到的Shadowed Implicit Value Members项目中的
隐含信息被重载为, ,和 ... , 并将调用隐式转换, , 或. 而只为 定义,它会调用隐式转换。 也就是说,将与 相同。 仍然存在一个问题: 为什么of会超载,而of
==CharShortFloat
==int2doubleint2floatint2long
equals()Anyint2Integer
Int.equals()java.lang.Integer.equals()


==AnyValequals()AnyVal是不是超载了?

4

2 回答 2

11

相关讨论是描述性的

== 2010 年的规范

和投机的

从 2011 年开始重新思考平等

FWIW,该规范在 12.2 中呼吁数值类型的相等性。

或者,在 HTML 中。(引用在底部,下面。)

在 2010 年的“pidgin spec-ese”中,Paul Phillips 是这样说的:

用 == 比较两个基元(装箱或未装箱)应该始终给出通过将这些值作为未装箱基元比较得到的结果。当您直接调用 equals 时,您将跳过所有软化逻辑,而是将其视为 java 的理论,即两个不同类型的装箱值始终不相等。

除了 12.5 中对Predef. 您通常不需要知道原语何时以其“盒装”形式存储,除非您出于性能原因需要这样做。

因此,例如,这些值会被默默地拆箱并为您提升:

scala> val ds = List(7.0)
ds: List[Double] = List(7.0)

scala> val is = List(7)
is: List[Int] = List(7)

scala> ds(0) == is(0)
res24: Boolean = true

scala> :javap -
  Size 1181 bytes
  MD5 checksum ca732fd4aabb301f3ffe0e466164ed50
  Compiled from "<console>"
[snip]
     9: getstatic     #26                 // Field .MODULE$:L;
    12: invokevirtual #30                 // Method .ds:()Lscala/collection/immutable/List;
    15: iconst_0      
    16: invokevirtual #36                 // Method scala/collection/immutable/List.apply:(I)Ljava/lang/Object;
    19: invokestatic  #42                 // Method scala/runtime/BoxesRunTime.unboxToDouble:(Ljava/lang/Object;)D
    22: getstatic     #47                 // Field .MODULE$:L;
    25: invokevirtual #50                 // Method .is:()Lscala/collection/immutable/List;
    28: iconst_0      
    29: invokevirtual #36                 // Method scala/collection/immutable/List.apply:(I)Ljava/lang/Object;
    32: invokestatic  #54                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
    35: i2d           
    36: dcmpl     

你注意到我有点惊讶

2.0 == BigInt(2)  // So far, nothing is strange.

对我来说,这有点神奇。BoxesRunTime.equals正如保罗菲利普斯所描述的那样。

     9: ldc2_w        #22                 // double 2.0d
    12: invokestatic  #29                 // Method scala/runtime/BoxesRunTime.boxToDouble:(D)Ljava/lang/Double;
    15: getstatic     #34                 // Field scala/package$.MODULE$:Lscala/package$;
    18: invokevirtual #38                 // Method scala/package$.BigInt:()Lscala/math/BigInt$;
    21: iconst_2      
    22: invokevirtual #44                 // Method scala/math/BigInt$.apply:(I)Lscala/math/BigInt;
    25: invokestatic  #48                 // Method scala/runtime/BoxesRunTime.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z

这是规范,供参考,以这种形式基本上只是承诺做正确的事情:

equals 方法测试参数是否为数值类型。如果这是真的,它将执行适合该类型的 == 操作。也就是数值类型的equals方法可以认为是这样定义的:

def equals(other: Any): Boolean = other match {
  case that: Byte   => this == that
  case that: Short  => this == that
  case that: Char   => this == that
  case that: Int    => this == that
  case that: Long   => this == that
  case that: Float  => this == that
  case that: Double => this == that
  case _ => false
}
于 2013-09-03T05:56:49.990 回答
2

我希望这样做是因为自动装箱和希望与 Java 的期望保持一致,以及一般的数学(1 = 1.0 = 1(表示为长)等)。例如,在 Scala 数值类型和 Java 数值类型之间运行比较:

scala> val foo: Long = 3L
foo: Long = 3

scala> val bar: Int = 3
bar: Int = 3

scala> foo == bar
res0: Boolean = true

scala> foo.equals(bar)
res1: Boolean = false

和....相比:

scala> val jfoo = new java.lang.Long(3L)
jfoo: Long = 3

scala> val jbar = new java.lang.Integer(3)
jbar: Integer = 3

scala> jfoo == jbar
res2: Boolean = true

scala> jfoo.equals(jbar)
res3: Boolean = false
于 2013-08-28T04:41:38.373 回答