💬

[Kotlin] lambda の仕組み

2022/02/25に公開

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