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-高阶函数(内联函数)_kotlin_02
​​​最终代码:消除了所有的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-高阶函数(内联函数)_lambda_03
​​​但是如果声明成内联函数:​

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-高阶函数(内联函数)_lambda表达式_04

序号

Tips

1

此时return代表返回外层的调用函数,main函数

特殊情况
`绝大多数高阶函数可以直接声明成内联函数,少数情况:

inline fun readRunnable(block: () -> Unit) {
var runnable = Runnable {
block()
}
runnable.run()
}

【kotlin】Kotlin笔记17-高阶函数(内联函数)_lambda表达式_05

序号

原因

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()
}