正如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