Scala和尾递归

ams*_*ams 4 scala tail-recursion

Stack Overflow上有各种答案,它解释了Scala中尾递归的条件.我理解限制以及如何以及在哪里可以利用尾递归.我不理解的部分是为什么存在对私有或最终方法的限制.

我还没有研究过Scala编译器如何在字节码级别将递归函数实际转换为非递归函数,但我们假设它执行类似下面的操作.我有一个Foo具有递归函数的类mod:

class Foo {
  def mod(value: Int, denom: Int): Int = {
    if(denom <= 0 || value <= 0) 0
    else if(0 <= value && value < denom) value
    else mod(value - denom, denom)
  }
}
Run Code Online (Sandbox Code Playgroud)

这是一个基本的模数函数,我想Scala编译器转换为某种伪Java-Scala,如:

class Foo {
  def mod(value: Int, denom: Int): Int = {
    if(denom <= 0 || value <= 0) return 0
    while(value > denom) value -= denom
    return value
  }
}
Run Code Online (Sandbox Code Playgroud)

(我可以相信我搞砸了那个翻译,但我不认为细节很重要..)

所以现在假设我是子类Foo:

class Bar extends Foo {
  def mod(value:Int, denom: Int): Int = 1
}
Run Code Online (Sandbox Code Playgroud)

是什么阻止了它的工作?当JVM有一个Foo/Bar并且mod被调用时,为什么解决mod应该使用的函数存在问题.为什么这与基函数是非递归的情况有什么不同?

我可以看到的一些可能的原因是:

  1. 无论出于何种原因,Scala编译器的实现都不能处理这个问题(如果是这样的话就足够了.如果是这样,是否有计划改变这个?)

  2. Foomod功能被改写的,以mod-non-recursive在编译期间因此Foo实际上并没有一个mod覆盖方法.

Dan*_*ral 8

我刚刚回答了这个问题,但让我们举个例子.假设您定义了类Foo,并将其作为JAR文件提供.

然后我得到那个Jar文件,并以这种方式扩展你的Foo:

class Bar extends Foo {
  def mod(value:Int, denom: Int): Int = {
    Logger.log("Received mod with "+value+" % "+denom)
    super.mod(value, denom)
}
Run Code Online (Sandbox Code Playgroud)

现在,当Foo mod自称,因为我的对象是a Bar,而不是a Foo,你应该(并且确实)去Bar mod,而不是Foo.

因为这是真的,你无法按照你所展示的方式对其进行优化.

子类的合约是,当超类在自身上调用方法时,如果该方法被重写,则它将是要调用的子类的方法.

将方法声明为private,使其成为final或类 - 甚至创建递归函数而不是方法,所有这些都确保您不必去子类实现.