[Kotlin] inline 用途


Posted by imcloudwu on 2022-01-06

class NoInlineClass {

    private fun runLambda(block: () -> Unit) {
        println("runLambda start")
        block()
        println("runLambda end")
    }

    fun run() {
        println("start")
        runLambda {
            println("runLambda")
        }
        println("end")
    }
}

會被編譯成

public final class NoInlineClass {
   private final void runLambda(Function0 block) {
      String var2 = "runLambda start";
      boolean var3 = false;
      System.out.println(var2);
      block.invoke();
      var2 = "runLambda end";
      var3 = false;
      System.out.println(var2);
   }

   public final void run() {
      String var1 = "start";
      boolean var2 = false;
      System.out.println(var1);
      this.runLambda((Function0)null.INSTANCE);
      var1 = "end";
      var2 = false;
      System.out.println(var1);
   }
}

Java透過Function0回調來實現Lambda
所以每次run()被呼叫時,都會產生 Function0 INSTANCE
頻繁呼叫就會產生大量INSTANCE,若是capturing lambda會變得更糟糕

inline

class InlineClass {

    private inline fun runLambda(block: () -> Unit) {
        println("runLambda start")
        block()
        println("runLambda end")
    }

    fun run() {
        println("start")
        runLambda {
            println("runLambda")
        }
        println("end")
    }
}
public final class InlineClass {
   private final void runLambda(Function0 block) {
      int $i$f$runLambda = 0;
      String var3 = "runLambda start";
      boolean var4 = false;
      System.out.println(var3);
      block.invoke();
      var3 = "runLambda end";
      var4 = false;
      System.out.println(var3);
   }

   public final void run() {
      String var1 = "start";
      boolean $i$f$runLambda = false;
      System.out.println(var1);
      $i$f$runLambda = false;
      String var3 = "runLambda start";
      boolean var4 = false;
      System.out.println(var3);
      int var5 = false;
      String var6 = "runLambda";
      boolean var7 = false;
      System.out.println(var6);
      var3 = "runLambda end";
      var4 = false;
      System.out.println(var3);
      var1 = "end";
      $i$f$runLambda = false;
      System.out.println(var1);
   }
}

簡單說,inline fun裡的程式碼會被整段複製
不再產生Function0 INSTANCE

Local & Non-local return

class API {

    private fun doSomeThing(block: () -> Unit) {
        println("start api")
        block()
        println("finish api")
    }

    fun callAPI() {
        doSomeThing {
            println("test api")
            return //錯誤, IDE提示 'return' is not allowed here
            return@doSomeThing //正確, 但 println("finish api")會被執行
        }
    }
}

加入inline前,只允許使用 return@doSomeThing ,這是local return,只能跳離Lambda block
加入inline後,可以使用 return ,這是non-local return,可以跳離整個fun

noinline

不複製該段lambda

private inline fun doSomeThing(block1: () -> Unit, noinline block2: () -> Unit)

crossinline

不允許該段lambda使用non-local return

class API {

    private inline fun doSomeThing(crossinline block1: () -> Unit) {
        println("start api")
        block1()
        println("finish api")
    }

    fun callAPI() {
        doSomeThing {
            return //Not allowed
            return@doSomeThing //Only allowed this
        }
    }
}

ref: https://stackoverflow.com/questions/44471284/when-to-use-an-inline-function-in-kotlin


#Android #Kotlin







Related Posts

為什麼需要 React / 思考模式的差異 / state vs props

為什麼需要 React / 思考模式的差異 / state vs props

OAuth 2.0 (Open Authorization)

OAuth 2.0 (Open Authorization)

串接 API -- try catch 練習

串接 API -- try catch 練習


Comments