正如Rex Kerr指出的,这是应用尾部调用优化的Scala编译器。如果你想知道到底是编译的,你可以用一个额外的参数运行编译器:
scalac -Xprint:tailcalls yourfile.scala
这将tailcalls
编译阶段之后打印中间表示。在接下来的输入(如果您想了解所有阶段,还可以运行scalac -Xshow-phases
)。例如,:
object TailRec {
def foo(l : List[Int]) : Unit = l match {
case Nil => Thread.dumpStack()
case x :: xs => println(x); foo(xs)
}
}
编译器将打印(用于功能foo
):
def foo(l: List[Int]): Unit = {
<synthetic> val _$this: TailRec.type = TailRec.this;
_foo(_$this,l){
l match {
case immutable.this.Nil => java.this.lang.Thread.dumpStack()
case (hd: Int, tl: List[Int])collection.immutable.::[Int]((x @ _), (xs @ _)) => {
scala.this.Predef.println(x);
_foo(TailRec.this, xs)
}
}
}
}
部分_foo(_$this,l)
看起来像一个函数定义,但它实际上是一个标签,而“调用”_foo(TailRec.this, xs)
实际上是跳转到该标签。简而言之,编译器将递归调用重新编写为真正的while循环。
编译器会在可以时自动应用优化。如果你想确保一个函数被正确地重写,你可以使用@tailrec
对它进行注释,如果编译器不能优化它,编译器会产生一个错误。
-1请更清楚:提供短代码样本和REPL抄本来说明问题。 – retronym