所谓尾递归,就是方法的递归调用在方法体的最后。scala编译器会把尾递归的字节码优化成循环执行的形式,但有一个限制可能会被你们忽略.先看一个例子:java
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) } }
下面是执行结果,能够看出递归调用的方式比循环方式慢了不少,并且有次数越多慢的幅度越大的倾向。 shell
922 969 2406 2032 13578 8047
咱们对approximate加上@tailrec注释,从新编译。这时编译器给出了错误:app
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能突破这些限制,那是一件很是振奋人心的事
函数