The use of Lambda in Kotlin 4. Inline function inline

1. Inline functions

        Functions modified with the keyword inline are called inline functions. Inline modification is a higher-order function that uses functions as parameters. If you modify an ordinary function, it will be a warning. Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types, and the impact of ordinary function inlining on performance is negligible.

2. The benefits of using inline to modify higher-order functions

        We use ordinary function declarations and inline function declarations for high-order functions in Kotlin and then convert them into Java code and compare them. kotlin code:

class Test {
    //不使用inline 修饰的高阶函数
    fun test(f: () -> Unit) {
        f()
    }
    //使用inline 修饰的高阶函数
    inline fun testInline(f: () -> Unit) {
        f()
    }
    fun call() {
        test { print("test") }
        testInline { print("testInline") }
    }
}

java code:

public final class Test {
   public final void test(@NotNull Function0 f) {
      Intrinsics.checkNotNullParameter(f, "f");
      f.invoke();
   }

   public final void testInline(@NotNull Function0 f) {
      int $i$f$testInline = 0;
      Intrinsics.checkNotNullParameter(f, "f");
      f.invoke();
   }

   public final void call() {
      this.test((Function0)null.INSTANCE);
      int $i$f$testInline = false;
      int var3 = false;
      String var4 = "testInline";
      boolean var5 = false;
      System.out.print(var4);
   }
}

        It can be seen in the call that this function is called directly when calling a non-inline function, and the anonymous class Function0 is created for calling the Lambda function. Inline functions copy the function body instead of creating an anonymous class, but directly embed the Lambdafunction implementation body.

        When a higher-order function is not Inlinedecorated, calling this function will directly reference this function, and an anonymous class will be created to implement the call of this function parameter. This has two parts of overhead. Directly calling this function will create an additional stack frame and push it onto the stack. Pop operation (a function call is a process of pushing and popping a stack frame), and the creation of anonymous classes will also consume performance. Using Inline to modify higher-order functions will improve performance.

         When calling an inline function, based on the above we already know that inlining will Lambdaembed the parameter function body directly, and inlining may lead to an increase in the generated code; however, if we use it properly (that is, avoid inlining too large functions ), the performance will Improvements have been made, especially at "megamorphic" calls in loops.

3. Disable inline noinline

        If you wish to inline only a portion of the lambda expression parameters passed to the inline function, you can use  noinline modifiers to mark the function parameters that you do not want inline:

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { //…… }

        Inlineable lambda expressions can only be called inside inline functions or passed as arguments to inlineable functions . Noinline modification is required when passed as a parameter of a non-inline function or stored in a field.

inline fun testInline(f1: () -> Unit,  f: () -> Unit) {
    f1.invoke()
    val a = f//会提示错误,内联Lambad 不能参数赋值
    testInlineInner(f) //会提示错误,内联Lambad 不能作为普通函数参数进行传递
}

fun testInlineInner(f: () -> Unit) {
    f()
}
inline fun testInline(f1: () -> Unit,  noinline f: () -> Unit) {
    f1.invoke()
    val a = f//可以
    testInlineInner(f) //可以
}

4. Use return (non-local return) in lambda expressions in inline functions

        In Kotlin, we can only exit using a normal, unqualified return from a named or anonymous function. To exit a lambda expression, we must use a label. The use of bare inside a lambda expression is prohibited  returnbecause a lambda expression cannot cause the function containing it to return.

fun testInlineInner(f: () -> Unit) {
    f()
}
testInlineInner {
        return//'return' is not allowed here
    }

But if the function passed by the lambda expression is inline, the return can also be inlined, so it is allowed. This kind of return (located in the lambda expression, but exiting the function containing it) is called a non-local return .

inline fun testInlineInner(f: () -> Unit) {
    f()
}

fun main(args: Array<String>) {
    testInlineInner {
        return// 可以,退出main函数
    }
}

5. crossinline

        When inlining Lambdais not called directly in the function body, but is called in a nested function or other execution environment, it needs to be declared ascrossinline。

inline fun f(crossinline body: () -> Unit) {
   val f = Runnable { body() }
}

六、Parameters of type Reified

        reified is Kotlin's keyword about generics, so that generics are not erased. If you need to use reified to modify the generic type in a generic method, you need to use Inline to modify the generic method, because the Inline function can specify the generic type. The type type is not erased, because the inline function will embed the bytecode into the place where it is called during compilation, so the compiler will know the specific type corresponding to the generic. Using reified and Inline is suitable for generic methods, and the method It is necessary to judge the generic type in the body. ​​​​​​​

inline fun <reified T> Bundle.plus(key: String, value: T) {
    when (value) {
        is String -> putString(key, value)
        is Long -> putLong(key, value)
        is Int -> putInt(key, value)
    }
}

7. Inline attributes

inlineYou can also modify setthe getmethod, and you can directly modify the properties so that both accessors are marked asinline。

class Amount(var amount: Long) {
    private val isEmpty: Boolean
        inline get() {
            return amount <= 0
        }

    private val isEmptyNoInline: Boolean
        get() {
            return amount <= 0
        }

    fun test(){
       val amount = Amount(10)
        val isEmpty = amount.isEmpty
        val isEmptyNoInline = amount.isEmptyNoInline
    }
    //转化为Java代码
    public final void test() { 
      Amount amount = new Amount(10L);
      int $i$f$isEmpty = false;
      boolean isEmpty = amount.getAmount() <= 0L; //代码嵌入
      boolean isEmptyNoInline = amount.isEmptyNoInline(); //非嵌入
   }
}

1. Introduction to the use of Lambda expressions in the collection functional API

2. Function types and instantiation

3. SAM conversion (Single Abstract Method Conversions)

4. Inline function inline

Guess you like

Origin blog.csdn.net/old_land/article/details/119612708