在之前介绍中,我们了解到Lambda表达式实际上是会带来额外的内存和性能开销的。那么Kotlin是怎么来消除这些开销呢?答案就是内敛函数!
内敛函数定义语法与普通函数的区别只是在函数的加个inline的标记,用于标记此函数数内联函数,定义如下:
inline fun 函数名([函数参数列表]) [:返回类型]{
[函数体]
}
具体可看下面一段代码:
inline fun test(number1: Int, number2: Int, block: (Int, Int) -> Int): Int {
return block(number1, number2)
}
内敛函数实现原理
内联函数是为了消除高阶函数需要额外的内部匿名类和创建匿名类实例对象以及二次函数调用带来的性能损耗,实际上它是将调用内联函数的地方全部替换为内联函数体,我们通过举例来分析其原理:
kotlin代码:
inline fun test(number1: Int, number2: Int, block: (Int, Int) -> Int): Int {
return block(number1, number2)
}
fun main() {
test(1, 2) { num1, num2 ->
num1 num2
}
}
反编译后的Java代码:
public static final int test(int number1, int number2, @NotNull Function2 block) {
int $i$f$test = 0;
Intrinsics.checkNotNullParameter(block, "block");
return ((Number)block.invoke(number1, number2)).intValue();
}
public static final void main() {
byte number1$iv = 1;
int number2$iv = 2;
int var10000 = number1$iv number2$iv;
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
通过上面反编译后的代码,可以看出内敛函数在调用时直接将函数体内容移到了执行的地方。
非内联(noinline)局部取消内联作用
为什么需要非内敛函数?
因为内联的函数类型参数在编译的时候会被进行代码替换,因此它没有真正的参数属性。非内联的函数类型参数可以自由地传递给其他任何函数,因为它就是一个真实的参数,而内联的函数类型参数只允许传递给另外一个内联函数,这也是它最大的局限性。此外,内联和非内联有一个重要的区别:内联函数所引用的Lambda表达式中是可以使用return关键字来进行函数返回的,而非内联函数只能进行局部返回。
inline fun test(block1: (Int, Int) -> Int, noinline block2: () -> Unit): () -> Unit {
block1(1,2)
return block2
}
上面一段代码,如果去掉block2前面的noinline关键字,则代码会直接报错。
总结内联函数可以消除高阶函数需要额外的内部匿名类和创建匿名类实例对象以及二次函数调用带来的性能损耗,但是因为通过将内联函数的内部语句替换为调用语句的原理,所以会增加代码量,使用内联函数要避免内联函数的内部语句不要过大,因为会导致多个地方调用内联函数的地方都替换为内联函数的内部语句,导致代码量大量增多,从而增加app的包大小。
可以将内联函数的原理理解为:内联函数的函数体语句是一个副本,经过编译之后会将内联函数的函数体语句拷贝解构并替换调用内联函数的语句。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved