为什么除非方法是最终的,否则 Scala 编译器不会应用尾调用优化? [英] Why won't the Scala compiler apply tail call optimization unless a method is final?

查看:45
本文介绍了为什么除非方法是最终的,否则 Scala 编译器不会应用尾调用优化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么除非方法是最终的,否则 Scala 编译器不会应用尾调用优化?

Why won't the Scala compiler apply tail call optimization unless a method is final?

例如:

class C {
    @tailrec def fact(n: Int, result: Int): Int =
        if(n == 0)
            result
        else
            fact(n - 1, n * result)
}

结果

错误:无法优化@tailrec 注释方法:它既不是私有的也不是最终的,因此可以被覆盖

error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden

如果编译器在这种情况下应用TCO,究竟会出现什么问题?

What exactly would go wrong if the compiler applied TCO in a case such as this?

推荐答案

考虑以下与 REPL 的交互.首先我们用阶乘方法定义一个类:

Consider the following interaction with the REPL. First we define a class with a factorial method:

scala> class C {
         def fact(n: Int, result: Int): Int =
           if(n == 0) result
           else fact(n - 1, n * result)
       }
defined class C

scala> (new C).fact(5, 1)
res11: Int = 120

现在让我们在子类中覆盖它,使超类的答案翻倍:

Now let's override it in a subclass to double the superclass's answer:

scala> class C2 extends C {
         override def fact(n: Int, result: Int): Int = 2 * super.fact(n, result)
       }
defined class C2

scala> (new C).fact(5, 1)
res12: Int = 120

scala> (new C2).fact(5, 1)

您希望最后一次通话的结果是什么?您可能期望 240.但不是:

What result do you expect for this last call? You might be expecting 240. But no:

scala> (new C2).fact(5, 1)
res13: Int = 7680

那是因为当超类的方法进行递归调用时,递归调用会通过子类.

That's because when the superclass's method makes a recursive call, the recursive call goes through the subclass.

如果覆盖工作使得 240 是正确答案,那么在这里的超类中执行尾调用优化将是安全的.但这不是 Scala(或 Java)的工作方式.

If overriding worked such that 240 was the right answer, then it would be safe for tail-call optimization to be performed in the superclass here. But that isn't how Scala (or Java) works.

除非方法被标记为 final,它在进行递归调用时可能不会调用自己.

Unless a method is marked final, it might not be calling itself when it makes a recursive call.

这就是为什么除非方法是最终的(或私有的)否则 @tailrec 不起作用.

And that's why @tailrec doesn't work unless a method is final (or private).

更新:我建议您也阅读其他两个答案(John 和 Rex 的).

UPDATE: I recommend reading the other two answers (John's and Rex's) as well.

这篇关于为什么除非方法是最终的,否则 Scala 编译器不会应用尾调用优化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆