Scala for the Impatient Chapter 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
的差异......
当我尝试这样做时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
(,要么更有可能的是,您正在查看Test
类的javap
输出,而不是Test$
。例如,请参阅 Scala 中的编程以获取更多详细信息:
对于每个 Scala 单例对象,编译器将创建一个 Java 对象的类,末尾添加了美元符号。对于一个 名为
App
的单例对象,编译器生成一个名为App$
.这个类具有 Scala 的所有方法和字段 单例对象。
如果列出已编译的目录的内容,则会看到Test.class
和Test$.class
。使用javap -v Test$
将向您展示后者,这是您会发现差异的地方。