它是Scala 2.8.0中的错误吗? (2.8.1.RC2也是如此)
import junit.framework._ import Assert._ class BugTest extends TestCase { def compare(first: Any, second: Any): Int = { (first, second) match { case (k: Int, o: Int) => k compare o //why the next case matches (Float, Int) but does not match (Int, Float) ??? case (k: Number, o: Number) => k.doubleValue() compare o.doubleValue() case _ => throw new Exception("Unsupported compare " + first + "; " + second) } } def testCompare() { assertEquals("Both Int", -1, compare(0, 1)) assertEquals("Both Float", 1, compare(1.0, 0.0)) assertEquals("Float then Int", 0, compare(10.0, 10)) assertEquals("Int then Float", 0, compare(10, 10.0))//this fails with an exception } }
答案 0 :(得分:3)
我认为这是一个错误。如果你看一下生成的字节码:
public int compare(java.lang.Object, java.lang.Object);
Code:
Stack=4, Locals=7, Args_size=3
0: aload_1
1: astore_3
2: aload_2
3: astore 4
5: aload_3
6: instanceof #8; //class java/lang/Integer
9: ifeq 81
12: aload_3
13: invokestatic #14; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
16: istore 5
18: aload 4
20: instanceof #8; //class java/lang/Integer
23: ifeq 45
26: getstatic #20; //Field scala/Predef$.MODULE$:Lscala/Predef$;
29: iload 5
31: invokevirtual #24; //Method scala/Predef$.intWrapper:(I)Lscala/runtime/RichInt;
34: aload 4
36: invokestatic #14; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
39: invokevirtual #29; //Method scala/runtime/RichInt.compare:(I)I
42: goto 124
45: new #31; //class java/lang/Exception
//part omitted for brevity..
81: aload_3
82: instanceof #54; //class java/lang/Number
85: ifeq 161
88: aload_3
89: checkcast #54; //class java/lang/Number
92: astore 6
94: aload 4
96: instanceof #54; //class java/lang/Number
99: ifeq 125
102: getstatic #20; //Field scala/Predef$.MODULE$:Lscala/Predef$;
105: aload 6
107: invokevirtual #58; //Method java/lang/Number.doubleValue:()D
110: invokevirtual #62; //Method scala/Predef$.doubleWrapper:(D)Lscala/runtime/RichDouble;
113: aload 4
115: checkcast #54; //class java/lang/Number
118: invokevirtual #58; //Method java/lang/Number.doubleValue:()D
在第6行中,检查第一个变量是java.lang.Integer
的实例。如果这不成功,我们继续第81行,该行以java.lang.Number
检查开始。如果第一个变量是整数,那么我们继续对第二个变量进行相同的检查。但是,如果第二次检查没有成功,而不是再次在第81行继续进行数字检查,则跳转到第45行,这将引发异常。这似乎不正确。我很快浏览了trac,但无法直接找到关于此的问题,因此创建一个可能是明智的。
修改强> 正如Extempore指出的那样,这是一个已经存在于trac中的错误,请参阅下面的评论。
答案 1 :(得分:2)
我不知道具体问题的答案,但这是定义比较的另一种方式:
def compare[A : Numeric, B: Numeric](first: A, second: B): Int =
implicitly[Numeric[A]].toDouble(first) compare implicitly[Numeric[B]].toDouble(second)
scala> compare(0.0,1.0)
res30: Int = -1
scala> compare(0.0,1)
res31: Int = -1
scala> compare(0,1.0)
res32: Int = -1
scala> compare(0,1)
res33: Int = -1