Kotlin函数 ⑦ ( 内联函数 | Lambda 表达式弊端 | “ 内联 “ 机制避免内存开销 - 将使用 Lambda 表达式作为参数的函数定义为内联函数 | 内联函数本质 - 宏替换 )

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin函数 ⑦ ( 内联函数 | Lambda 表达式弊端 | “ 内联 “ 机制避免内存开销 - 将使用 Lambda 表达式作为参数的函数定义为内联函数 | 内联函数本质 - 宏替换 )相关的知识,希望对你有一定的参考价值。

文章目录





一、内联函数



1、Lambda 表达式弊端


Lambda 表达式弊端 :

Lambda 表达式 灵活使用 , 是以 牺牲内存开销为代价的 ;

Java 虚拟机中 , Lambda 表达式 是以 实例对象 的形式 , 存储在堆内存中的 , 这就产生了内存开销 ;


2、" 内联 " 机制避免内存开销


" 内联 " 机制避免内存开销 :

在 Kotlin 语言中提供了一种 " 内联 " 机制 ,

解决了上面的 Lambda 表达式的 内存开销 问题 ,

使用 Lambda 表达式 作为参数的函数 定义为 inline 内联函数 ,

Java 虚拟机就 不会再为 lambda 表达式 在堆内存中 创建 实例对象 了 ,

这样就 避免了 Lambda 表达式 的内存开销 ;


3、内联函数本质 - 编译时宏替换


内联函数使用 :

在使用 Lambda 表达式的时候 ,

Kotlin 编译器直接将 inline 内联函数函数体 直接拷贝到 使用位置 ;

内联函数 类似于 C 语言中的 预编译指令 宏定义 , 在编译时直接替换拷贝宏定义内容 ;

Kotlin 中的 内联函数 也是一种 编译时 进行 宏替换的操作 ;


4、内联函数不能递归


内联函数不能递归 :

如果 将函数 定义为 内联函数 ,

则该函数 不能进行递归操作 ,

递归操作 会导致 函数体的 无限复制粘贴 ,

编译器会报警 ;





二、普通函数代码示例



代码示例 : 下面的代码中 studentDoSomething 是普通函数 ;

fun main() 
    // 定义函数类型变量, 之后作为函数参数传递给函数
    val actionFun =  name: String, age: Int ->
        "student $name $age years old, say hello"
    

    // 调用 studentDoSomething 函数, 输入姓名, 年龄, 执行的操作
    studentDoSomething("Tom", 18, actionFun);


fun studentDoSomething(name: String, age: Int,
                       action: (String, Int) -> String) 
    val act = action(name, age);
    println(act)

将字节码转换为 Java 代码内容如下 :

import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = 1, 1, 16,
   bv = 1, 0, 3,
   k = 2,
   d1 = "\\u0000\\u001c\\n\\u0000\\n\\u0002\\u0010\\u0002\\n\\u0002\\b\\u0002\\n\\u0002\\u0010\\u000e\\n\\u0000\\n\\u0002\\u0010\\b\\n\\u0000\\n\\u0002\\u0018\\u0002\\n\\u0000\\u001a\\u0006\\u0010\\u0000\\u001a\\u00020\\u0001\\u001a0\\u0010\\u0002\\u001a\\u00020\\u00012\\u0006\\u0010\\u0003\\u001a\\u00020\\u00042\\u0006\\u0010\\u0005\\u001a\\u00020\\u00062\\u0018\\u0010\\u0007\\u001a\\u0014\\u0012\\u0004\\u0012\\u00020\\u0004\\u0012\\u0004\\u0012\\u00020\\u0006\\u0012\\u0004\\u0012\\u00020\\u00040\\b¨\\u0006\\t",
   d2 = "main", "", "studentDoSomething", "name", "", "age", "", "action", "Lkotlin/Function2;", "KotlinDemo"
)
public final class HelloKt 
   public static final void main() 
      Function2 actionFun = (Function2)null.INSTANCE;
      studentDoSomething("Tom", 18, actionFun);
   

   // $FF: synthetic method
   public static void main(String[] var0) 
      main();
   

   public static final void studentDoSomething(@NotNull String name, int age, @NotNull Function2 action) 
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(action, "action");
      String act = (String)action.invoke(name, age);
      boolean var4 = false;
      System.out.println(act);
   





三、内联函数代码示例



代码示例 : 下面的代码中 studentDoSomething 是内联函数 ;

fun main() 
    // 定义函数类型变量, 之后作为函数参数传递给函数
    val actionFun =  name: String, age: Int ->
        "student $name $age years old, say hello"
    

    // 调用 studentDoSomething 函数, 输入姓名, 年龄, 执行的操作
    studentDoSomething("Tom", 18, actionFun);


inline fun studentDoSomething(name: String, age: Int,
                       action: (String, Int) -> String) 
    val act = action(name, age);
    println(act)

将字节码转换为 Java 代码内容如下 :

import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = 1, 1, 16,
   bv = 1, 0, 3,
   k = 2,
   d1 = "\\u0000\\u001c\\n\\u0000\\n\\u0002\\u0010\\u0002\\n\\u0002\\b\\u0002\\n\\u0002\\u0010\\u000e\\n\\u0000\\n\\u0002\\u0010\\b\\n\\u0000\\n\\u0002\\u0018\\u0002\\n\\u0000\\u001a\\u0006\\u0010\\u0000\\u001a\\u00020\\u0001\\u001a3\\u0010\\u0002\\u001a\\u00020\\u00012\\u0006\\u0010\\u0003\\u001a\\u00020\\u00042\\u0006\\u0010\\u0005\\u001a\\u00020\\u00062\\u0018\\u0010\\u0007\\u001a\\u0014\\u0012\\u0004\\u0012\\u00020\\u0004\\u0012\\u0004\\u0012\\u00020\\u0006\\u0012\\u0004\\u0012\\u00020\\u00040\\bH\\u0086\\b¨\\u0006\\t",
   d2 = "main", "", "studentDoSomething", "name", "", "age", "", "action", "Lkotlin/Function2;", "KotlinDemo"
)
public final class HelloKt 
   public static final void main() 
      Function2 actionFun = (Function2)null.INSTANCE;
      String name$iv = "Tom";
      int age$iv = 18;
      int $i$f$studentDoSomething = false;
      String act$iv = (String)actionFun.invoke(name$iv, Integer.valueOf(age$iv));
      boolean var5 = false;
      System.out.println(act$iv);
   

   // $FF: synthetic method
   public static void main(String[] var0) 
      main();
   

   public static final void studentDoSomething(@NotNull String name, int age, @NotNull Function2 action) 
      int $i$f$studentDoSomething = 0;
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(action, "action");
      String act = (String)action.invoke(name, age);
      boolean var5 = false;
      System.out.println(act);
   

以上是关于Kotlin函数 ⑦ ( 内联函数 | Lambda 表达式弊端 | “ 内联 “ 机制避免内存开销 - 将使用 Lambda 表达式作为参数的函数定义为内联函数 | 内联函数本质 - 宏替换 )的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin系列之letwithrunapplyalso函数的使用

Kotlin inline 内联函数

Kotlin 协程Flow 异步流 ⑦ ( 调用 FlowCollector#emit 发射元素时自动执行 Flow 流的取消检测 | 启用检测 Flow 流的取消cancellable函数 )

Kotlin 协程Flow 异步流 ⑦ ( 调用 FlowCollector#emit 发射元素时自动执行 Flow 流的取消检测 | 启用检测 Flow 流的取消cancellable函数 )

Kotlin内联函数和Android方法都很重要

Kotlin also let 内联扩展函数