为什么==运算符和equals()在Scala中对AnyVal的值表现不同 [英] Why == operator and equals() behave differently for values of AnyVal in Scala

查看:93
本文介绍了为什么==运算符和equals()在Scala中对AnyVal的值表现不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In the scaladoc of scala.Any, the operator == (or, method ==) is explained:


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

对于 AnyRef 子类的对象,我很容易理解,但是我没有看不到任何奇怪的东西。

For objects of subclasses of AnyRef, I can understand it easily, and I didn't see any strange things.

但是,对于 AnyVal 的值,(我的意思是 Int Double Long 等),上述定义有些棘手( 1 eq null ?如果我们不将 1 转换为java.lang.Integer,则不会编译该对象)。此外, == equals()的行为也不同。

However, for values of AnyVal, (I mean Int, Double, Long, and so on,) the above definition is somewhat tricky (1 eq null? This does not compile if we do not convert 1 to java.lang.Integer). Also, == and equals() behave differently.

我会举一些例子。


scala> 1 == 1
res0: Boolean = true

scala> 1 == 1.0
res1: Boolean = true

scala> 1 == 1.2
res2: Boolean = false

scala> 2 == BigInt(2)
res3: Boolean = true

scala> 2.0 == BigInt(2)
res4: Boolean = true

scala> 2 == BigInt(3)
res5: Boolean = false

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

So far, nothing is strange. But if we do the same things with equals() methods,


scala> 1 equals 1
res7: Boolean = true

scala> 1 equals 1.0
res8: Boolean = false

scala> 1 equals 1.2
res9: Boolean = false

scala> 2 equals BigInt(2)
res10: Boolean = false

scala> 2.0 equals BigInt(2)
res11: Boolean = false

scala> 2 equals BigInt(3)
res12: Boolean = false

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

So if the types are different, equals() always returns false, whereas == tests if they represent the same value if they are converted to the same type.

对于 AnyRef 的子类,方法 == equals()返回相同值。

In the case of subclass of AnyRef, methods == and equals() return the same.


scala> BigInt(2) == 2
res25: Boolean = true

scala> BigInt(2) == 2.0
res26: Boolean = true

scala> BigInt(3) == 2
res27: Boolean = false

scala> BigInt(2) equals 2
res28: Boolean = true

scala> BigInt(2) equals 2.0
res29: Boolean = true

scala> BigInt(3) equals 2
res30: Boolean = false

所以,为什么方法 == equals() AnyVal 有区别吗?

So, why methods == and equals() are diffrent for AnyVal?

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

I'm using Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25).

编辑1

我看到==不能直接被覆盖,因为根据在Scala中编程,第二版

编辑2

尽管有答案,但我的问题仍然存在。我将保留这个问题。



对应于 scala.Int scala的内容Java中的Long 是Java的原始类型 int long

在Java中, java.lang.Integer java.lang.Long 是类,因此它们的变量是引用,可以为 null
这意味着它们就像Scala中的 AnyRef 。不是 AnyVal

Scala的 AnyVal - scala.Int scala.Long 不能具有 null 值,Java的也不能int long

另外, java.lang.Integer 在Java中的 == 用于引用相等(与Scala中的 eq 相同)。

在Scala REPL中使用 java.lang.Integer 所获得的内容与在纯Java项目中使用.java源文件所获得的内容完全不同。



但是,我在Java中使用原始类型的类所能得到的是:(THIS IS JAVA)

EDIT 2
Although there is an answer, my question remains. I will leave this question open.

What correspond to scala.Int and scala.Long in Java are Java's primitive types int and long.
In Java, java.lang.Integer and java.lang.Long are classes, so their variables are references, which can have null. That means, they are like AnyRef in Scala. Not AnyVal.
Scala's AnyVal - scala.Int and scala.Long cannot have null values, neither can Java's int and long.
Also, java.lang.Integer's == in Java is for reference equality (same as eq in Scala).
What you get using java.lang.Integer in Scala REPL will be quite different from what you get with it in pure Java Project with .java source file in this respect.

However, what I could get from using classes of primitive types in Java was: (THIS IS 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))));
    }
}

输出:


true
false
false
true
false


是的,它们的行为类似于scala AnyVal的 equals()。但是,为什么会这样呢?

Yes, they behave similar to scala AnyVal's equals(). But, then, why does this happen?

Scala的 AnyVal == 对应于Java原始类型的 ==

,并使用Scala的AnyVal的 equals()对应于Java类类型的 equals()

用BigInt进行相等性测试怎么样? Java中没有相应的原始类型。

问题仍然存在...

Does Scala's AnyVal's == correspond to == of Java's primitive type
and does Scala's AnyVal's equals() correspond to equals() of Java's class types?
What about equality tests with BigInt? There is no corresponding primitive type in Java.
The question remains...

编辑3

我可以从scaladoc找到一些信息。 ( http://www.scala-lang.org/api/ current / index.html#scala.Int

隐式隐含价值成员项目中的隐式信息

我可以找到 == 对于 Char Short Float 和...,

== 将调用隐式转换 int2double int2float int2long

equals()仅为 Any 定义,它将调用隐式转换 int2Integer

Int.equals()将与 java.lang.Integer.equals()



仍然有一个问题:

为什么 == AnyVal 重载,而 equals() AnyVal 中的c>是否未过载?

EDIT 3
I could find some information from scaladoc. (http://www.scala-lang.org/api/current/index.html#scala.Int)
The Implicit information from the item of Shadowed Implicit Value Members,
I could find == was overloaded for Char, Short, Float, and ...,
and == will call implicit conversions int2double, int2float, or int2long.
Whereas equals() is only defined for Any, and it will call implicit conversion int2Integer.
That is, Int.equals() will be the same as java.lang.Integer.equals().

One question remains:
Why == of AnyVal is overloaded, and equals() of AnyVal is not overloaded?

推荐答案

相关的d问题是描述性的

The relevant discussions are the descriptive

2010年==的规范

和投机性

< a href = https://groups.google.com/d/msg/scala-internals/MhIR30mYt-M/MHD0VHhMqoQJ rel = noreferrer>重新思考2011年以来的平等

FWIW,该规范要求数值类型在1​​2.2中

FWIW, the spec calls out equality for numeric value types in 12.2.

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

Or, in HTML. (Quote at bottom, below.)

保罗·菲利普斯(Paul Phillips)在2010年的 pidgin spec-ese中这样说:

In his "pidgin spec-ese" of 2010, Paul Phillips puts it this way:


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

comparing two primitives (boxed or unboxed) with == should always give the result you would have gotten by comparing those values as unboxed primitives. When you call equals directly, you are skipping all that softening logic and instead treated to java's theory that two boxed values of different types are always unequal.

除了在12.5中对 Predef 提供的转换的传递引用外,该规范没有提及盒装基元。通常,您并不需要知道何时将原语以其装箱形式存储,除非出于性能原因当然需要这样做。

The spec doesn't speak of boxed primitives, aside from a passing reference in 12.5 to the conversions provided by Predef. You're not generally meant to be aware of when a primitive is stored in its "boxed" form, unless of course you need to for performance reasons.

因此,对于例如,这些值会自动为您取消装箱并升级:

So, for example, these values are silently unboxed and promoted for you:

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.

对我来说,这有点神奇。如Paul Phillips所述,它会调用 BoxesRunTime.equals

To me, that's slightly magical. It calls into BoxesRunTime.equals as described by Paul Phillips.

     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

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

Here is the spec, for reference, which in this form basically just promises to do the right thing:


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

The equals method tests whether the argument is a numeric value type. If this is true, it will perform the == operation which is appropriate for that type. That is, the equals method of a numeric value type can be thought of being defined as follows:



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
}

这篇关于为什么==运算符和equals()在Scala中对AnyVal的值表现不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆