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
}
最終代碼:消除了所有的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")
}
但是如果聲明成内聯函數:
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")
}
序号 | Tips |
1 | 此時return代表傳回外層的調用函數,main函數 |
特殊情況
`絕大多數高階函數可以直接聲明成内聯函數,少數情況:
inline fun readRunnable(block: () -> Unit) {
var runnable = Runnable {
block()
}
runnable.run()
}
序号 | 原因 |
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()
}