huy*_*hjl 91 scala tail-call-optimization
我认为有一个@tailrec注释可以确保编译器优化尾递归函数.你刚才把它放在宣言面前吗?如果在脚本模式中使用Scala(例如:load <file>在REPL 下使用),它是否也有效?
Von*_*onC 112
来自" Tail calls,@ tailrec和trampolines "博文:
- 在Scala 2.8中,您还可以使用新
@tailrec注释来获取有关哪些方法已优化的信息.
此注释允许您标记希望编译器将优化的特定方法.
如果编译器没有优化它们,您将收到警告.- 在Scala 2.7或更早版本中,您需要依靠手动测试或检查字节码来确定方法是否已经过优化.
例:
您可以添加
@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)
}
}
Run Code Online (Sandbox Code Playgroud)
它适用于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 = {
^
Run Code Online (Sandbox Code Playgroud)
Dav*_*ith 39
Scala编译器将自动优化任何真正的尾递归方法.如果您使用注释注释一个您认为是尾递归的方法@tailrec,那么编译器将警告您该方法实际上是否为尾递归.这使得@tailrec注释成为一个好主意,既可以确保方法当前是可优化的,也可以在修改时保持优化.
请注意,如果可以覆盖Scala,则Scala不会将该方法视为尾递归.因此,该方法必须是私有的,最终的,对象(与类或特征相对),或者是要优化的另一个方法.
ret*_*nym 23
注释是scala.annotation.tailrec.如果该方法不能进行尾调用优化,则会触发编译器错误,如果出现以下情况,则会发生
它放在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 {
^
Run Code Online (Sandbox Code Playgroud)
哎呀!最后一次调用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
Run Code Online (Sandbox Code Playgroud)
请注意,它length0是自动私有的,因为它是在另一个方法的范围内定义的.