我来自面向对象的背景,我主要用Java编写应用程序。我最近开始在Scala上探索更多,我一直在阅读一些文字。因此我遇到了一种称为尾递归的东西。我明白了如何编写尾递归方法。
例如 - 要在List中添加元素(当然这可以使用reduce方法完成)但是为了理解,我写了一个尾递归方法:
@scala.annotation.tailrec
def sum(l: List[Int], acc: Int): Int = l match {
case Nil => acc
case x :: xs => sum(xs, acc + x)
}
Scala运行时如何在内部处理此递归?
答案 0 :(得分:3)
Scala运行时如何在内部处理此递归?
不是。它在编译时由编译器处理。
尾递归相当于while
循环。因此,尾递归方法可以编译为while
循环,或者更确切地说,它可以编译为while
循环编译的相同方式。当然,完全的编译方式取决于所使用的编译器。
目前有三种主要的Scala实现,它们是Scala-native(一种针对具有自己的运行时的本机机器代码的编译器),Scala.js(一种针对ECMAScript平台的编译器,位于ECMAScript运行时的顶部) ),以及混乱的JVM实现Scala也被称为" Scala"就像语言一样(针对JVM平台并使用JVM运行时)。曾经有一个Scala.NET,但不再主动维护。
我将在这个答案中专注于Scala-JVM。
我将使用与您的示例略有不同的示例,因为模式匹配的编码实际上相当复杂。让我们从最简单的尾递归函数开始:
def foo(): Unit = foo()
这由Scala-JVM编译为以下JVM字节码:
public void foo()
0: goto 0
还记得我上面说过尾递归相当于循环吗?好吧,JVM没有循环,它只有GOTO
。这与while
循环完全相同:
def bar(): Unit = while (true) {}
获取编译为:
public void bar()
0: goto 0
还有一个更有趣的例子:
def baz(n: Int): Int = if (n <= 0) n else baz(n-1)
编译为:
public int baz(int);
0: iload_1
1: iconst_0
2: if_icmpgt 9
5: iload_1
6: goto 16
9: iload_1
10: iconst_1
11: isub
12: istore_1
13: goto 0
16: ireturn
如您所见,它只是一个while
循环。