scala – 为什么函数尾不是递归的?

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

Functions like approximate,which call themselves as their last
action,are called 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)

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)

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

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

解决方法

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

Main.scala:12: error: Could not optimize @tailrec annotated method test: it is neither private nor final so can be overridden

实际上,如果你将方法设为最终,它会按预期工作.

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...