无法优化方法

Could not optimize methods

这是引发编译错误的最小代码 'Recursive call not in tail position'。但是,我在尾部位置使用 @inline 和递归调用 is。我使用这个 @inline 的原因是我将原始 reccall 的代码复制了两次。

import scala.annotation._
object Test {
  @tailrec private def test(i: Int): Int = {
    @inline def reccall(i: Int): Int = test(i-1)
    i match {
      case 0 => 0
      case i => reccall(i)
    }
  }
}

我查看了答案 ,但它们不适用于我的情况。使用 Scala 2.12

好了,JVM中尾递归的实现机制解释如下:

Scala, in the case of tail recursion, can eliminate the creation of a new stack frame and just re-use the current stack frame. The stack never gets any deeper, no matter how many times the recursive call is made.

因此,在您的情况下,它不能重用属于 test 方法的当前堆栈帧,因为无论如何它都必须为 reccall 方法创建一个新的堆栈帧。

在这种情况下,递归调用是隐式的,由另一种方法进行。所以我相信你不能真的为这种情况实现尾递归。

您可以完全删除 reccall 方法并编写 case i => test(i-1) 然后编译器将不会报错。

注意:我也相信 @inline 在这里与此无关,并且在这个例子中不是必需的,因为如果我删除它 - 编译器仍然会抱怨同样的原因。

这里的问题是 @inline 只是建议性的:它不保证编译器会内联该函数。由于 @tailrec 仅在绝对保证可以消除尾调用时才有效,这意味着使用 @tailrec 必须假设没有内联。

看来,@inline的实现方式还是栈传参。通过插入内联代码消除了跳转,但堆栈仍用于参数。这样就不可能处于tail位置,因为调用完成后需要清理栈

此外,用 @inline 注释函数并不能 保证 优化器将内联它,只是它会 "try especially hard"。