虽然经过@tailrec
问题描述:
我期待到斯卡拉TCO并写了下面的代码虽然经过@tailrec
import scala.annotation.tailrec
final def tailReccursionEx(str:String):List[String]={
@tailrec
def doTailRecursionEx(str:String,pos:Int,accu:List[String]):List[String]={
if(pos==str.length) return accu
else{
doTailRecursionEx(str,pos+1,accu++accu.foldLeft(List[String](str(`pos`).toString)){
(l,ch)=>l:+ch+str(`pos`)})
}
}
doTailRecursionEx(str,0,List[String]())
}
我已经通过了@tailrec测试,我相信我的功能就是我的Scala代码没有得到TCO'ed自递归尾部呼叫。然而,当我看着到Java字节代码
javap -c -private RecursionEx\$\$anonfun\$doTailRecursionEx\$1\$1
我看不到所承诺的转到的TCO自我递归函数。这是字节码。
public RecursionEx$$anonfun$doTailRecursionEx$1$1(java.lang.String, int);
Code:
0: aload_0
1: aload_1
2: putfield #35; //Field str$2:Ljava/lang/String;
5: aload_0
6: iload_2
7: putfield #41; //Field pos$1:I
10: aload_0
11: invokespecial #93; //Method scala/runtime/AbstractFunction2."<init>":()V
14: return
}
答
我想你需要在不同的生成的类文件上运行javap
。您目前正在检查的文件对应于您使用的作为foldLeft
的一部分的封闭文件。如果您尝试查看“RecursionEx $ .class”文件,您应该看到尾部调用递归。当我编译代码:
import scala.annotation.tailrec
object RecursionEx {
@tailrec
final def doTailRecursionEx(str: String, pos: Int, accu: List[String]): List[String] = {
if (pos == str.length) return accu
doTailRecursionEx(str, pos + 1 , accu ++ accu.foldLeft(List[String](str(`pos`).toString)) {
(l, ch) => l :+ ch + str(`pos`)
})
}
def main(args: Array[String]) {
doTailRecursionEx("mew",0,List[String]())
}
}
,然后运行javap -c -private RecursionEx$
我看到了对代码的相关部分如下:末
public final scala.collection.immutable.List doTailRecursionEx(java.lang.String, int, scala.collection.immutable.List);
Code:
0: iload_2
1: aload_1
2: invokevirtual #21; //Method java/lang/String.length:()I
5: if_icmpne 10
8: aload_3
9: areturn
10: iload_2
11: iconst_1
12: iadd
13: aload_3
14: aload_3
15: getstatic #26; //Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$;
18: getstatic #31; //Field scala/Predef$.MODULE$:Lscala/Predef$;
21: iconst_1
22: anewarray #17; //class java/lang/String
25: dup
26: iconst_0
27: getstatic #31; //Field scala/Predef$.MODULE$:Lscala/Predef$;
30: aload_1
31: invokevirtual #35; //Method scala/Predef$.augmentString:(Ljava/lang/String;)Lscala/collection/immutable/StringOps;
34: iload_2
35: invokeinterface #41, 2; //InterfaceMethod scala/collection/immutable/StringLike.apply:(I)C
40: invokestatic #47; //Method scala/runtime/BoxesRunTime.boxToCharacter:(C)Ljava/lang/Character;
43: invokevirtual #53; //Method java/lang/Object.toString:()Ljava/lang/String;
46: aastore
47: checkcast #55; //class "[Ljava/lang/Object;"
50: invokevirtual #59; //Method scala/Predef$.wrapRefArray:([Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
53: invokevirtual #62; //Method scala/collection/immutable/List$.apply:(Lscala/collection/Seq;)Lscala/collection/immutable/List;
56: new #64; //class RecursionEx$$anonfun$doTailRecursionEx$1
59: dup
60: aload_1
61: iload_2
62: invokespecial #67; //Method RecursionEx$$anonfun$doTailRecursionEx$1."<init>":(Ljava/lang/String;I)V
65: invokeinterface #73, 3; //InterfaceMethod scala/collection/LinearSeqOptimized.foldLeft:(Ljava/lang/Object;Lscala/Function2;)Ljava/lang/Object;
70: checkcast #75; //class scala/collection/TraversableOnce
73: getstatic #26; //Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$;
76: invokevirtual #79; //Method scala/collection/immutable/List$.canBuildFrom:()Lscala/collection/generic/CanBuildFrom;
79: invokevirtual #85; //Method scala/collection/immutable/List.$plus$plus:(Lscala/collection/TraversableOnce;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object;
82: checkcast #81; //class scala/collection/immutable/List
85: astore_3
86: istore_2
87: goto 0
与goto
,正如你所期望的。