什么是Scala注释来确保尾recursion函数被优化?

我认为有@tailrec注释,以确保编译器将优化尾recursion函数。 你只是把它放在宣言前面? 如果在脚本模式下使用Scala(例如在REPL下使用:load <file> ),它也可以工作吗?

从“ 尾巴呼叫,@ tailrec和蹦床 ”博客文章:

  • 在Scala 2.8中,您还可以使用新的@tailrec注释来获取有关优化哪些方法的信息。
    这个注解可以让你标记你希望编译器优化的特定方法。
    如果它们没有被编译器优化,你将会得到一个警告。
  • 在Scala 2.7或更早版本中,您将需要依靠手动testing或字节码检查来确定方法是否已经优化。

例:

你可以添加一个@tailrec注释,这样你就可以确定你的改变已经发挥作用了。

 import scala.annotation.tailrec class Factorial2 { def factorial(n: Int): Int = { @tailrec def factorialAcc(acc: Int, n: Int): Int = { if (n <= 1) acc else factorialAcc(n * acc, n - 1) } factorialAcc(1, n) } } 

它从REPL( Scala REPL提示和技巧中的例子)

 C:\Prog\Scala\tests>scala Welcome to Scala version 2.8.0.RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_18). Type in expressions to have them evaluated. Type :help for more information. scala> import scala.annotation.tailrec import scala.annotation.tailrec scala> class Tails { | @tailrec def boom(x: Int): Int = { | if (x == 0) throw new Exception("boom!") | else boom(x-1)+ 1 | } | @tailrec def bang(x: Int): Int = { | if (x == 0) throw new Exception("bang!") | else bang(x-1) | } | } <console>:9: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position @tailrec def boom(x: Int): Int = { ^ <console>:13: error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden @tailrec def bang(x: Int): Int = { ^ 

Scala编译器会自动优化任何真正的尾recursion方法。 如果您使用@tailrec注释来注释一个您认为是尾recursion的@tailrec ,那么编译器会警告您该方法是否实际上不是尾recursion。 这使得@tailrec注释是一个好主意,既可以确保方法当前可优化,并且在修改时仍然可以优化。

请注意,如果可以重写,Scala不会考虑一个方法是尾recursion的。 因此,该方法必须是私有的,最终的,在对象上(而不是类或特征),或者在另一种方法中被优化。

注释是scala.annotation.tailrec 。 如果该方法不能被尾调用优化,则会触发编译器错误,如果发生以下情况:

  1. recursion调用不在尾部位置
  2. 该方法可以被重写
  3. 该方法不是最终的(前面的特例)

它放在方法定义的def之前。 它在REPL中起作用。

在这里我们导入注解,并尝试将方法标记为@tailrec

 scala> import annotation.tailrec import annotation.tailrec scala> @tailrec def length(as: List[_]): Int = as match { | case Nil => 0 | case head :: tail => 1 + length(tail) | } <console>:7: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position @tailrec def length(as: List[_]): Int = as match { ^ 

哎呀! 最后一个调用是1.+() ,不是length() ! 我们来重新说一下这个方法:

 scala> def length(as: List[_]): Int = { | @tailrec def length0(as: List[_], tally: Int = 0): Int = as match { | case Nil => tally | case head :: tail => length0(tail, tally + 1) | } | length0(as) | } length: (as: List[_])Int 

请注意, length0是自动专用的,因为它是在另一个方法的范围内定义的。