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

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐