我有一个函数,我知道它是尾递归的。但是由于我定义它的方式,编译器抱怨函数在非尾部位置具有递归调用。这就是功能。
@tailrec
def travel: (Int, List[Char]) => Int = {
case (n, Nil) => n
case (n, '~' :: sls) => travel(0, sls)
case (n, '^' :: sls) => travel(max(n-1,0), sls)
case (n, '>' :: sls) => travel(n+1, sls)
case (_, s :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'")
}
我得到了
error: could not optimize @tailrec annotated method travel: it contains a recursive call not in tail position
def travel: (Int, List[Char]) => Int = {
如果我这样写,它就可以了。
@tailrec
def travel(n:Int, l:List[Char]): Int = (n,l) match {
case (n, Nil) => n
case (n, '~' :: sls) => travel(0, sls)
case (n, '^' :: sls) => travel(max(n-1,0), sls)
case (n, '>' :: sls) => travel(n+1, sls)
case (_, s :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'")
}
我认为它与def: (Input) => Output = {}
类型声明样式有关。我使用它是因为它看起来比编写嵌套匹配更清晰,或者在元组上匹配。
答案 0 :(得分:7)
两者不一样。在第一种情况下,方法生成一个函数,然后再次调用该方法(生成函数等)。也就是说,每次在第一种情况下调用Function1[(Int, List[Char]), Int]
时,您都会创建travel
的新实例。不出所料,这不能转换成跳转指令。 (理论上可以,但分析会非常复杂,因为必须取消所有这些对象创作。)
在第二种情况下,它只是一个调用自身的方法,可以转换为跳转。