Scala for the Impatient 第15章练习10:将assert(n >= 0
添加到factorial
方法。在启用断言的情况下进行编译,并验证factorial(-1)
是否会引发异常。无需断言即可编译。怎么了?使用javap
检查断言调用发生了什么。
我的代码:
object Test {
def factorial(x: Int): Int = {
assert(x >= 0, "Call to factorial must be >= 0!")
x match {
case 0 => 1
case x: Int => x * factorial(x - 1)
}
}
def main(args: Array[String]): Unit = {
factorial(-1)
}
}
我首先使用scalac
编译,使用javap Test
进行检查,然后使用scalac -Xelide-below MAXIMUM
再次编译并使用相同的命令进行检查 - 我似乎无法找到两者之间的区别
我理解使用断言进行编译会在我尝试执行程序时抛出异常,而没有断言的编译会导致堆栈溢出错误,但我找不到javap
中的差异......
答案 0 :(得分:5)
当我使用javap -v
尝试此操作时,我在启用了断言的版本中找到以下行,但在另一行中没有:
20: invokevirtual #27; //Method scala/Predef$.assert:(ZLscala/Function0;)V
...
27: if_icmpne 34
30: iconst_1
31: goto 55
所以当然看起来没问题。
问题可能是你要么没有查看字节码(需要-c
或-v
标志到javap
),要么更可能 - 你'重新审视javap
类Test
的输出,而不是Test$
。有关更多详细信息,请参阅 Programming in Scala :
对于每个Scala单例对象,编译器都将创建一个Java 具有美元符号的对象的类添加到结尾。为一个 单件对象名为
App
,编译器生成一个名为的Java类App$
。该类包含Scala的所有方法和字段 单身对象。
如果列出您编译的目录的内容,您将看到Test.class
和Test$.class
。使用javap -v Test$
会向您显示后者,您可以在这里找到差异。