💬
[Kotlin] lambda の仕組み
Kotlin lambda の仕組み
つまり
- 純粋関数?とクロージャーでは、JVM での命令が違う。
- 純粋関数では、関数がシングルトンパターンのクラスとして表現される。
- クロージャーでは、定義時環境の値をフィールドとして持つクラスとして表現され、new して実行される。
実験コード 1
fun main(){
val f = {i: Int -> i * 2}
f(10)
}
$ kotlinc ./Lambda.kt -include-runtime -d ./Lambda.jar
$ unzip Lambda.jar
$ javap -p -v -s -constants LambdaKt.class
public static final void main();
descriptor: ()V
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Code:
stack=2, locals=1, args_size=0
0: getstatic #12 // Field LambdaKt$main$f$1.INSTANCE:LLambdaKt$main$f$1;
3: checkcast #14 // class kotlin/jvmeno
6: astore_0
7: aload_0
8: bipush 10
10: invokestatic #20 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
13: invokeinterface #24, 2 // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
18: pop
19: return
LambdaKt$main$f$1
なる inner class の INSTANCE の invoke メソッドを呼んでいます。
{i: Int -> i * 2}
をシングルトンパターンのクラスとして表現される。
実験コード 2
fun main(){
val t = 2
val f = {i: Int -> i * t}
f(10)
}
$ javap -p -v -s -constants LambdaKt.class
public static final void main();
descriptor: ()V
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Code:
stack=3, locals=2, args_size=0
0: iconst_2
1: istore_0
2: new #8 // class LambdaKt$main$f$1
5: dup
6: iload_0
7: invokespecial #12 // Method LambdaKt$main$f$1."<init>":(I)V
10: checkcast #14 // class kotlin/jvm/functions/Function1
13: astore_1
14: aload_1
15: bipush 10
17: invokestatic #20 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
20: invokeinterface #24, 2 // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
25: pop
26: return
LambdaKt$main$f$1
という inner class を new して、invoke メソッドを呼んでいます。
いわゆるクロージャーですね。
Discussion