@tailrec如何工作
我已经使用并阅读了@tailrec
注释以获得一个尾递归方法。 我经历了很多解释它的链接。 例如,它只适用于自我调用功能,不应该被覆盖等。
在任何地方都提到compiler optimizes
。 但是编译器做了什么魔术/概念来使其尾递归。 对于下面的简单函数,编译器做了什么:
@tailrec def fact(acc: Int, n: Int): Int = {
if (n <= 1) acc
else fact(n * acc, n - 1)
}
fact(1,10)
我的意思是它会将它转换成循环,并重复调用它,然后返回最终值? 有没有解释它的纸张的链接
除了我对你的问题的评论(在这里重新输入代码):
var acc = 1
var n = 10
start:
if (n <= 1) return acc
else {
acc = n * acc
n = n - 1
goto start
}
我尝试编译fact
方法,使用最近的构建,我刚刚碰到的和scalac -Xprint:all
编译器发出了一个icode
文件。 所以这真的说明了它如何优化尾部呼叫:
// methods
def fact(acc: Int (INT), n: Int (INT)): Int {
locals: value acc, value n, value _$this
startBlock: 1
blocks: [1,2,3,4,5]
1:
2 JUMP 2
2: // huynhjl's comment: IF condition is here
3 LOAD_LOCAL(value n)
3 CONSTANT(1)
3 CJUMP (INT)LE ? 3 : 4
3: // huynhjl's comment: first branch of IF, will return acc
3 LOAD_LOCAL(value acc)
3 JUMP 5
5:
2 RETURN(INT)
4: // huynhjl's comment: else branch of IF, update acc and n and jump back
4 LOAD_LOCAL(value n)
4 LOAD_LOCAL(value acc)
4 CALL_PRIMITIVE(Arithmetic(MUL,INT))
4 LOAD_LOCAL(value n)
4 CONSTANT(1)
4 CALL_PRIMITIVE(Arithmetic(SUB,INT))
4 STORE_LOCAL(value n)
4 STORE_LOCAL(value acc)
4 JUMP 2
}
这是一个很好的博客文章
@tailrec
只保证如果编译器无法执行尾部调用优化,则会发出错误。 Scala默认执行尾部呼叫优化。
当满足纸张所描述的条件时,可以保留最后一帧而不是一堆帧,并执行循环。 这个过程在这里有更好的描述
链接地址: http://www.djcxy.com/p/80519.html下一篇: What techniques are available for memory optimizing in 8051 assembly language?