为什么==运算符和equals()在Scala中对AnyVal的值表现不同 [英] Why == operator and equals() behave differently for values of AnyVal in Scala
问题描述
在 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()$ c $
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
和投机性
< a href = https://groups.google.com/d/msg/scala-internals/MhIR30mYt-M/MHD0VHhMqoQJ rel = noreferrer>重新思考2011年以来的平等
FWIW,该规范要求数值类型在12.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屋!