有没有办法关闭Scala编译器的尾递归优化?

时间:2015-09-01 06:24:43

标签: scala tail-recursion

由于某些特殊原因,我想在大程序中删除所有@tailrec的效果,但是不想手动执行,编译时是否有任何可选参数可以关闭尾递归优化?我想在代码中留下@tailrec,但是不想检查它并在编译时进行尾递归优化。这可能吗?

2 个答案:

答案 0 :(得分:6)

您可以使用编译器的-g:notailcalls选项。

来自文档:

  

-g:{无,源,线,乏,notailcalls}

     

“none”不会生成调试信息,

     

“source”仅生成源文件属性

     

“line”生成源和行号信息,

     

“vars”生成源,行号和局部变量信息,

     

“notailcalls”生成以上所有内容,不会执行尾调用优化

请注意,正如文档所指定的那样,这也将启用调试信息生成

一个例子:

import scala.annotation.tailrec

class A {

@tailrec
final def x(i: Int): Int = if(i == 0) {i;} else {x(i-1)}

}
当“正常”编译时,javap -p -v A.class的{​​{1}}:

x

public final int x(int); descriptor: (I)I flags: ACC_PUBLIC, ACC_FINAL Code: stack=2, locals=2, args_size=2 0: iload_1 1: iconst_0 2: if_icmpne 7 5: iload_1 6: ireturn 7: iload_1 8: iconst_1 9: isub 10: istore_1 11: goto 0 编译时相同:

-g:notailcalls

重要位是位置public final int x(int); descriptor: (I)I flags: ACC_PUBLIC, ACC_FINAL Code: stack=3, locals=2, args_size=2 0: iload_1 1: iconst_0 2: if_icmpne 9 5: iload_1 6: goto 16 9: aload_0 10: iload_1 11: iconst_1 12: isub 13: invokevirtual #12 // Method x:(I)I 16: ireturn 上的invokevirtual

请注意,顺便说一句,jwvh谨慎地纠正了13的插入 - 它实际上并没有切换尾部优化,它唯一能做的就是如果它不能通知编译器失败插入尾调用优化,无论如何都会尝试

答案 1 :(得分:3)

@tailrec注释不会打开/关闭尾递归优化。如果带注释的例程正确尾递归,它只会告诉编译器输出错误。

如果例程是尾递归的,则无论是否注释,都会进行优化。

来自docs

  

一种方法注释,用于验证是否将编译该方法   尾调用优化。

     

如果存在,编译器将在方法时发出错误   无法优化成循环。

操作词是“验证”。

<强>更新

@mikołak是对的。快速检查显示-g:notailcalls标志会关闭注释验证。

%%> scalac tailrec.scala 
tailrec.scala:5: error: could not optimize @tailrec annotated method rf: it contains a recursive call not in tail position
def rf(x: Int): Int = if (x < 1) x else rf(x-2)+1
                                               ^
one error found
%%> scalac -g:notailcalls tailrec.scala 
%%>