容易被忽略的类成员方法的尾递归优化限制

本文探讨了Scala中尾递归的概念、优化限制及其在实际应用中的表现,通过实例展示了尾递归与循环调用在性能上的差异,并强调了在类中定义的函数进行尾递归优化的特定条件。

        所谓尾递归,就是方法的递归调用在方法体的最后。scala编译器会把尾递归的字节码优化成循环执行的形式,但有一个限制可能会被大家忽略.先看一个例子:

class Approx {
  def isGoodEnough(guess: Double): Boolean =
    if (guess < 1) true
    else false

  def improve(guess: Double): Double = guess - 1

  @tailrec
  final def approximate(guess: Double): Double =
    if (isGoodEnough(guess)) guess
    else approximate(improve(guess))

  def approximateLoop(initialGuess: Double): Double = {
    var guess = initialGuess
    while (!isGoodEnough(guess))
      guess = improve(guess)
    guess
  }
}

object TailRecDemo {
  val app = new Approx()

  def main(args: Array[String]) = {
    println(System.getProperty("java.class.path"))
    recursive(1)
    iterate(1)
    recursive(10)
    iterate(10)
    recursive(100)
    iterate(100)
  }

  def recursive(n: Int) = {
    val start = java.lang.System.currentTimeMillis()
    for (i <- 0 to 10000000) {
      app.approximate(n)
    }
    println(java.lang.System.currentTimeMillis() - start)
  }

  def iterate(n: Int) = {
    val start = java.lang.System.currentTimeMillis()
    for (i <- 0 to 10000000) {
      app.approximateLoop(n)
    }
    println(java.lang.System.currentTimeMillis() - start)
  }

}

下面是执行结果,可以看出递归调用的方式比循环方式慢了很多,而且有次数越多慢的幅度越大的倾向。 

922
969
2406
2032
13578
8047

我们对approximate加上@tailrec注释,重新编译。这时编译器给出了错误:

  

error: could not optimize @tailrec annotated method approximate: it is neither private nor final so can be overridden def approximate(guess: Double): Double =

 

原来对于class中定义的函数,如果没有声明为final或private,那么编译器是不会对尾递归进行优化的。

Scala在尾递归的优化上有诸多限制,比如递归必须是直接递归而不能是间接的,也不能是通过函数对象调用实现的递归,假如scala能突破这些限制,那是一件非常振奋人心的事

转载于:https://my.oschina.net/aiguozhe/blog/40398

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值