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

use*_*007 2 scala tail-recursion

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

mik*_*łak 6

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

来自文档:

-g:{无,源,线,VARS,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)}

}
Run Code Online (Sandbox Code Playgroud)

javap -p -v A.classx时候编撰的"正常":

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
Run Code Online (Sandbox Code Playgroud)

同样,编译时-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
Run Code Online (Sandbox Code Playgroud)

重要的是invokevirtual位置13.


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