天天看點

【kotlin】Kotlin筆記17-高階函數(内聯函數)

Kotlin筆記17-高階函數-内聯函數

10.2 高階函數

  • 内聯函數的作用

​Example:​

fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
    return operation(num1, num2)
}

fun main() {
    val num1=100
    val num2=80
    val result1= num1AndNum2(num1,num2,::plus)
    val result2= num1AndNum2(num1,num2,::minus)
    println("result1 is $result1")
    println("result2 is $result2")
}      
序号 Tips
1 Kotlin最終要編譯成Java位元組碼
2 是以Kotlin編譯器會将高階函數的文法轉換成Java支援的文法結構
3 Lambda表達式在底層轉換成匿名類的實作方式

​轉換後的Java代碼:​

public static int num1Andnum2(int num1, int num2, Function operation) {
  int result = (int) operation.invoke(num1, num2);
}

public static void main() {
  int num1 = 100;
  int num2 = 80;
  int result = num1AndNum2(num1, num2, new Function() {
    @Override
    public Integer invoke(Interger n1, Interger n2) {
      return n1 + n2;
    }
  });
}      
序号 Tips
表明 每調用一次Lambda表達式,都會建立一個新的匿名類執行個體,造成額外的記憶體與性能開銷
是以 Kotlin提供内聯函數的功能, 消除運作開銷
inline: 加在高階函數前

​Example:​

inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
  val result = operation(num1, num2)
  return result
}      
【kotlin】Kotlin筆記17-高階函數(内聯函數)
【kotlin】Kotlin筆記17-高階函數(内聯函數)

​​

​最終代碼:消除了所有的Lambda運作開銷​

fun main3() {
    val num1 = 100
    val num2 = 80
    val result = num1 + num2
}      
  • noline與crossinline

noline: 内聯其中的Lambda表達式

​​

​Example:​

inline fun inlineTest(block1: ()-> Unit, noline block2: () -> Unit) {
}      
序号 Tips
1 内聯的函數參數類型參數在編譯的時候會被進行代碼替換,是以他沒有真正的參數屬性
2 内聯的函數類型參數隻允許傳遞給另外一個内聯函數(局限性)
3 非内聯函數類型參數可以自由傳遞給其他任何函數,其是真實的參數
4 内聯函數所引用的Lambda表達式中可以用return進行函數傳回
5 非内聯函數隻能進行局部傳回

​局部傳回:​

fun printString(str:String,block:(String)->Unit){
    println("printString begin")
    block(str)
    println("printString end")
}

fun main() {
    println("main start")
    var str=""
    printString(str){s->
        println("lambda start")
        if(s.isEmpty()) return@printString//局部傳回
        println(s)
        println("lambda end")
    }
    println("main end")
}      
【kotlin】Kotlin筆記17-高階函數(内聯函數)

​​

​但是如果聲明成内聯函數:​

inline fun printString(str:String,block:(String)->Unit){
    println("printString begin")
    block(str)
    println("printString end")
}

fun main() {
    println("main start")
    var str=""
    printString(str){s->
        println("lambda start")
        if(s.isEmpty()) return//局部傳回
        println(s)
        println("lambda end")
    }
    println("main end")
}      
【kotlin】Kotlin筆記17-高階函數(内聯函數)
序号 Tips
1 此時return代表傳回外層的調用函數,main函數

特殊情況

`絕大多數高階函數可以直接聲明成内聯函數,少數情況:

inline fun readRunnable(block: () -> Unit) {
  var runnable = Runnable {
    block()
  }
  runnable.run()
}      
【kotlin】Kotlin筆記17-高階函數(内聯函數)
序号 原因
1 我們在Runnable的Lambda表達式中調用傳入的函數參數類型
2 而Lambda在編譯的時候會被轉換成匿名類的實作方式,相當于,上述代碼在匿名類中調用了傳入的函數類型參數
3 内聯函數引用的Lambda表達式允許使用return傳回,但此時我們在匿名類中調用的函數類型參數,此時不可能進行外層調用函數傳回,隻能對匿名類中的函數調用進行傳回
4 如果我們在高階函數建立了另外的Lambda或者匿名類的實作,并且在這些實作中調用的函數類型參數,再将高階函數聲明成内聯函數,會報錯
5 内聯函數的Lambda表達式允許使用return關鍵字,和高階函數的匿名類實作中
corssinline: 保證内聯函數的Lambda表達式中一定不會使用return,但人可以使用return@runRunnable局部傳回
inline fun runRunnable(crossinline block: () -> Unit){
    val runnable= java.lang.Runnable {
        block()
    }
    runnable.run()
}      

繼續閱讀