为什么函数尾递归不是?

ste*_*lla 4 recursion scala tail-recursion

我正在阅读M. Odersky的Scala编程,他说

像approximate这样自称为最后一个动作的函数叫做tail recursive.

所以,我试过这个:

object Main extends App {
    implicit val mc = new MyClass(8)
    val ti = new TestImplct
    ti.test
}

class TestImplct {
  def test(implicit mc : MyClass): Unit = {
    println(mc.i)
    mc.i -= 1
    if(mc.i < 0){
      throw new IllegalArgumentException
    }
    test
  }
}

class MyClass(var i : Int)
Run Code Online (Sandbox Code Playgroud)

IDEONE DEMO

但它会生成以下堆栈跟踪

 Exception in thread "main" java.lang.IllegalArgumentException
    at TestImplct.test(Main.scala:13)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
    at TestImplct.test(Main.scala:15)
Run Code Online (Sandbox Code Playgroud)

这意味着它为每个递归调用生成一个新的堆栈帧.但最后一步是呼唤自己.什么是错的,如何让它尾递归?

为什么编译器不进行尾调用优化?

Tza*_*har 9

您可以尝试使用@tailrec注释标记方法.如果你这样做,编译将失败,并将告诉你为什么编译器无法优化它为尾递归:

Main.scala:12:错误:无法优化@tailrec带注释的方法测试:它既不是私有的也不是最终的,所以可以被覆盖

实际上,如果你制作方法final,它会按预期工作.