📜  Kotlin 内联函数

📅  最后修改于: 2022-05-13 01:55:36.857000             🧑  作者: Mango

Kotlin 内联函数

在 Kotlin 中,高阶函数或 lambda 表达式都存储为对象,因此函数对象和类的内存分配和虚拟调用可能会引入运行时开销。有时我们可以通过内联 lambda 表达式来消除内存开销。为了减少此类高阶函数或 lambda 表达式的内存开销,我们可以使用inline关键字,它最终要求编译器不分配内存,只需在调用处复制该函数的内联代码即可。例子:

Kotlin
fun higherfunc( str : String, mycall :(String)-> Unit) {
   
    // inovkes the print() by passing the string str
    mycall(str)
}
 
// main function
fun main(args: Array) {
    print("GeeskforGeeks: ")
    higherfunc("A Computer Science portal for Geeks",::print)
}


Kotlin
inline fun higherfunc( str : String, mycall :(String)-> Unit){
    // inovkes the print() by passing the string str
    mycall(str)
}
// main function
 fun main(args: Array) {
    print("GeeskforGeeks: ")
    higherfunc("A Computer Science portal for Geeks",::print)
}


Kotlin
var lambda = { println("Lambda expression") 
              return }      // normally lambda expression does not allow return
                           // statement, so gives compile time error
fun main(args: Array) {
    lambda()
}


Kotlin
var lambda1 = { println("Lambda expression")}
 
fun main(args: Array) {
    lambda1()
}


Kotlin
fun main(args: Array){
    println("Main function starts")
    inlinedFunc({ println("Lambda expression 1")
    return },      // inlined function allow return
                   // statement in lambda expression
                   // so, does not give compile time error
 
    { println("Lambda expression 2")} )
 
    println("Main function ends")
}
    // inlined function
inline fun inlinedFunc( lmbd1: () -> Unit, lmbd2: () -> Unit  ) { 
    lmbd1()
    lmbd2()
}


Kotlin
fun main(args: Array){
    println("Main function starts")
     inlinedfunc({ println("Lambda expression 1")
        return },     // It gives compiler error
         { println("Lambda expression 2")} )
 
    println("Main function ends")
}
 
inline fun inlinedfunc( crossinline lmbd1: () -> Unit, lmbd2: () -> Unit  ) {
    lmbd1()
    lmbd2()
}


Kotlin
fun main(args: Array){
    println("Main function starts")
    inlinedFunc({ println("Lambda expression 1")
        return },     // It does not compiler time error
        { println("Lambda expression 2")
            return } )    // It gives compiler error
 
    println("Main function ends")
}
 
inline fun inlinedFunc( lmbd1: () -> Unit, noinline lmbd2: () -> Unit  ) {
    lmbd1()
    lmbd2()
}


Kotlin
fun main(args: Array) {
    genericFunc()
}
 
inline fun  genericFunc() {
    print(T::class)
}


Kotlin
fun main(args: Array) {
    print(flag)
}
fun foo(i: Int ): Int{
    var a =  i
    return a
}
inline var flag : Boolean
    get() = foo(10 ) == 10
    set(flag) {flag}


字节码:与Java一样,Kotlin 也是独立于平台的语言,因此它首先转换为字节码。我们可以通过Tools -> Kotlin -> Show Kotlin Bytecode获取字节码。然后,反编译得到这个字节码。

在上面的字节码中,主要关注的部分是:

mycall.invoke(str)

mycall通过将字符串作为参数传递来调用打印函数。在调用 print() 时,它会创建一个额外的调用并增加内存开销。

它像

mycall(new Function() {
        @Override
        public void invoke() {
         //println statement is called here.
        }
    });

如果我们调用大量函数作为参数,它们中的每一个都会增加方法计数,那么对内存和性能有很大的影响。

在上面的程序中,内联关键字会做什么?

科特林

inline fun higherfunc( str : String, mycall :(String)-> Unit){
    // inovkes the print() by passing the string str
    mycall(str)
}
// main function
 fun main(args: Array) {
    print("GeeskforGeeks: ")
    higherfunc("A Computer Science portal for Geeks",::print)
}

字节码:

inline关键字的帮助下, println lambda 表达式以 System.out.println 的形式复制到主函数中,无需进一步调用。

非本地控制流

在 Kotlin 中,如果我们想从 lambda 表达式返回,那么 Kotlin 编译器不允许我们这样做。借助 inline 关键字,我们可以从 lambda 表达式本身返回并退出调用内联函数的函数。

Kotlin 在 Lambda 表达式中使用 return 的程序:

科特林

var lambda = { println("Lambda expression") 
              return }      // normally lambda expression does not allow return
                           // statement, so gives compile time error
fun main(args: Array) {
    lambda()
}

输出:

Error:(4, 5) Kotlin: 'return' is not allowed here

通常它不允许从 lambda 返回并给出错误。

科特林

var lambda1 = { println("Lambda expression")}
 
fun main(args: Array) {
    lambda1()
}

输出:

Lambda expression

通常没有它可以正常工作并打印声明。

Kotlin 在 Lambda 中使用 return 作为参数传递给内联函数的程序:

科特林

fun main(args: Array){
    println("Main function starts")
    inlinedFunc({ println("Lambda expression 1")
    return },      // inlined function allow return
                   // statement in lambda expression
                   // so, does not give compile time error
 
    { println("Lambda expression 2")} )
 
    println("Main function ends")
}
    // inlined function
inline fun inlinedFunc( lmbd1: () -> Unit, lmbd2: () -> Unit  ) { 
    lmbd1()
    lmbd2()
}

输出:

Main function starts
Lambda expression 1

说明:在这里,我们将两个 lambda 表达式作为参数传递给inlinedFunc()函数。在从 main 调用内联函数时,我们将两者都传递给它的参数。在内联函数中, lmbd1()调用了第一个表达式,并且 return 关键字强制 lambda 表达式本身和调用它的主函数退出。

跨线关键字

在上面的程序中,lambda 中的 return 退出了内联函数以及它的封闭函数。因此,要停止从 lambda 表达式返回,我们可以使用交叉线对其进行标记。如果在 Lambda 表达式中看到任何 return 语句,它将引发编译器错误。

例子:

科特林

fun main(args: Array){
    println("Main function starts")
     inlinedfunc({ println("Lambda expression 1")
        return },     // It gives compiler error
         { println("Lambda expression 2")} )
 
    println("Main function ends")
}
 
inline fun inlinedfunc( crossinline lmbd1: () -> Unit, lmbd2: () -> Unit  ) {
    lmbd1()
    lmbd2()
}

输出:

Error:(6, 9) Kotlin: 'return' is not allowed here

内线

在 Kotlin 中,如果我们只想将传递给内联函数的一些 lambda 表达式内联,我们可以使用 noinline 修饰符标记一些函数参数。

科特林

fun main(args: Array){
    println("Main function starts")
    inlinedFunc({ println("Lambda expression 1")
        return },     // It does not compiler time error
        { println("Lambda expression 2")
            return } )    // It gives compiler error
 
    println("Main function ends")
}
 
inline fun inlinedFunc( lmbd1: () -> Unit, noinline lmbd2: () -> Unit  ) {
    lmbd1()
    lmbd2()
}

输出:

Error:(11, 13) Kotlin: 'return' is not allowed here

具体类型参数

有时我们需要访问调用过程中传递的参数类型。我们必须在函数调用时简单地传递参数,我们可以使用 reified 修饰符检索参数的类型。

科特林

fun main(args: Array) {
    genericFunc()
}
 
inline fun  genericFunc() {
    print(T::class)
}

输出:

class kotlin.String

内联属性

内联函数将代码复制到调用位置,类似的 inline 关键字将内联属性访问器方法复制到调用位置。 inline 修饰符可用于没有支持字段的属性的访问器。

科特林

fun main(args: Array) {
    print(flag)
}
fun foo(i: Int ): Int{
    var a =  i
    return a
}
inline var flag : Boolean
    get() = foo(10 ) == 10
    set(flag) {flag}

输出:

true