Kotlin内联函数,参数化
在本教程中,我们将研究Kotlin内联函数。
接下来,我们将使用Reified Type Parameters。
Kotlin内联函数
我们之前已经讨论过Kotlin高阶函数和Lambda表达式。
在将函数作为参数传递时,它们非常有用。
但是这些函数是具有自己的回调以及随后的内存分配的对象。
让我们通过示例了解这些函数作为参数传递给内部的方式。
fun main(args: Array<String>) { println("Hey how are you doing") sampleFunction("theitroad.local", ::println) } fun sampleFunction(str: String, expression: (String) -> Unit) { println("This is Kotlin Inline Functions Tutorial") expression(str) }
运行时,sampleFunction
传递println
作为参数。
现在Kotlin是一种基于JVM的语言,因此所有内容都将转换为字节码。
让我们转到"工具" |"查看" |"上面的代码"。
科特林|显示字节码。
主要部分是" expression.invoke()"。
调用lambda表达式(println)将创建一个另外的调用,从而创建一个内存。
Java中的invoke方法如下所示:
expression(new Function() { @Override public void invoke() { //println statement is called here. } });
现在,如果我们将多个函数作为参数调用,则每个函数的总和将增加方法数量,并对内存和性能产生巨大影响。
内联函数进行救援!
内联函数通过在运行时向调用函数提供函数主体和所有内容,从而使函数调用变得平坦。
我们需要添加inline
修饰符来做到这一点。
因此,当调用sampleFunction时,上面的sampleFunction
看起来像下面的代码。
inline fun sampleFunction(str: String, expression: (String) -> Unit) { print("This is Kotlin Inline Functions Tutorial") expression(str) }
" inline"关键字将功能复制到呼叫站点。
这样可以节省另外的对象创建以调用参数函数,从而为您节省了内存。
现在通过反编译来查看字节码。
注意:println
lambda表达式在main函数本身中以System.out.println的形式扩展。
不再需要其他电话。
为什么不使每个函数都内联?
内联函数将代码复制到一个位置,从而增加了生成的代码。
当通过参数调用的函数已经具有大代码时,应避免使用。此外,内联函数无法访问封闭类的"私有"成员。
您必须将它们设置为"内部"
下面是使用内联函数的示例:
fun main(args: Array<String>) { normalFunction() } fun normalFunction() { println("This is normal function.") inlineFunctionExample({ println("Inlined Functions")},{ println("Instead of object creation it copies the code.")} ) } inline fun inlineFunctionExample(myFunction: () -> Unit, another: () -> Unit ) { myFunction() another() print("Finally it's working fine!") }
在上面的代码中,我们传递了许多lambda表达式。
所有这些都将在运行时复制。
以下是在IntelliJ中生成的字节码:
所有的println
lambda调用都在normalFunction
本身中被展平。
输出占用更少的内存。
内联允许非本地控制流
使用内联函数,您可以从lambda表达式本身返回,并退出调用内联函数的函数。
下面的代码片段演示了相同的内容。
fun main(args: Array<String>) { normalFunction() } fun normalFunction() { println("This is normal function.") inlineFunctionExample({ println("Inlined Functions") return},{ println("Instead of object creation it copies the code.")} ) println("This is normal function closing") } inline fun inlineFunctionExample(myFunction: () -> Unit, another: () -> Unit ) { myFunction() another() print("Finally it's working fine!") }
如您所见,内联函数及其封闭函数都已退出。
我们不能从作为普通函数(非内联函数)一部分的lambda表达式返回。
为了防止这种情况,我们可以将lambda表达式标记为" crossinline"。
如果在该lambda表达式中看到return语句,则会引发编译器错误。
fun normalFunction() { println("This is normal function.") inlineFunctionExample( { println("Inlined Functions") return //compiler error here }, { println("Instead of object creation it copies the code.")} ) println("This is normal function closing") } inline fun inlineFunctionExample(crossinline myFunction: () -> Unit, another: () -> Unit ) { myFunction() another() print("Finally it's working fine!") }
Noinline
" noinline"修饰符用于设置表达式在调用中不被"内联"。
fun main(args: Array<String>) { normalFunction() } fun normalFunction() { println("This is normal function.") inlineFunctionExample({ println("Inlined Functions")}, { println("Instead of object creation it copies the code.")} ) println("This is normal function closing") } inline fun inlineFunctionExample(myFunction: () -> Unit, noinline another: () -> Unit ) { myFunction() another() print("Finally it's working fine!") }
内联属性
属性还允许使用Kotlin内联关键字。
就像内联函数一样,它将内联属性访问器方法复制到调用站点。
内联属性不能有后备字段。
fun main(args: Array<String>) { print(x) } var i = 10 inline var x: Boolean get() = i == 11 set(x) { x}
我们也可以在get和set方法上分别设置内联。
修饰类型参数
参数的类型无法在代码中检索,因为它会在运行时删除。
对于内联函数,虽然可以使用Reified。
为了检索参数的类型,我们可以对其设置一个" reified"修饰符。
为什么这样做?内联函数会在运行时复制完整的函数,因此只要我们对其进行了具体化设置,参数的类型也将可用。
fun main(args: Array<String>) { getT<Double>() } inline fun <reified T> getT() { print(T::class) }