当前位置: 首页 > news >正文

kotlin知识体系(四) : inline、noinline、crossinline 关键字对应编译后的代码是怎样的 ?

kotlin中inline、noinline、crossinline 关键字的作用

在 Kotlin 里,inlinenoinlinecrossinline 这几个关键字和高阶函数紧密相关,它们能够对高阶函数的行为进行优化和控制。下面为你详细阐述它们的作用和原理。

inline 关键字

inline 关键字用于修饰高阶函数,其作用是在编译时将函数调用处替换为函数体本身,以此避免函数调用的开销,提高代码的执行效率。

示例代码
// 定义一个内联高阶函数
inline fun inlineFunction(block: () -> Unit) {
    block()
}

fun main() {
    inlineFunction {
        println("This is an inline function call.")
    }
}
代码解释

在上述示例中,inlineFunctioninline 关键字修饰。在编译时,inlineFunction 的调用会被替换为函数体内容,这样就不会有额外的函数调用开销。不过,使用 inline 也会使生成的字节码体积增大,因为函数体被复制到了调用处。

noinline 关键字

当高阶函数被 inline 修饰时,它的所有函数参数默认也会被内联。要是你不希望某个函数参数被内联,就可以使用 noinline 关键字。

示例代码
// 定义一个内联高阶函数,包含一个 noinline 参数
inline fun mixedFunction(inlineBlock: () -> Unit, noinline noInlineBlock: () -> Unit) {
    inlineBlock()
    noInlineBlock()
}

fun main() {
    mixedFunction(
        { println("This is an inline block.") },
        { println("This is a non - inline block.") }
    )
}
代码解释

在这个例子中,mixedFunction 是内联函数,inlineBlock 会被内联,而 noInlineBlock 由于使用了 noinline 关键字,不会被内联。noinline 通常用于需要将函数参数存储在变量中或者作为其他函数的返回值的情况。

crossinline 关键字

在使用 inline 修饰高阶函数时,内联函数参数里不允许有非局部返回(即从外层函数返回)。若需要在 Lambda 表达式中使用 return 语句,但又不想使用 noinline 来避免内联,就可以使用 crossinline 关键字。

示例代码
// 定义一个内联高阶函数,包含一个 crossinline 参数
inline fun crossInlineFunction(crossinline block: () -> Unit) {
    val wrapper = {
        block()
    }
    wrapper()
}

fun main() {
    crossInlineFunction {
        // 这里不能使用 return 进行非局部返回,但可以执行其他操作
        println("Inside crossinline block.")
    }
}
代码解释

在这个例子中,crossInlineFunction 是内联函数,block 参数使用了 crossinline 关键字。在 block 中不能使用非局部返回,但可以正常执行其他操作。这样既能保证参数被内联,又能在一定程度上控制返回行为。

综上所述,inlinenoinlinecrossinline 关键字在 Kotlin 中用于控制高阶函数及其参数的内联行为,有助于优化代码性能和控制函数返回逻辑。

kotlin中inline、noinline、crossinline 关键字对应编译后的代码是怎样的 ?

下面通过具体示例,详细分析 Kotlin 中 inlinenoinlinecrossinline 关键字在编译后代码的表现。

1. inline 关键字

Kotlin 代码示例
inline fun inlineFunction(block: () -> Unit) {
    println("Before block")
    block()
    println("After block")
}

fun main() {
    inlineFunction {
        println("Inside block")
    }
}
编译后代码分析

在编译时,inline 函数会被内联展开。上述代码编译后,大致等效于以下 Java 代码(Kotlin 编译成 JVM 字节码,这里用 Java 形式便于理解):

public class Main {
    public static void main(String[] args) {
        System.out.println("Before block");
        System.out.println("Inside block");
        System.out.println("After block");
    }
}

inlineFunction 的函数体直接替换了调用处的代码,避免了函数调用的开销。

2. noinline 关键字

Kotlin 代码示例
inline fun mixedFunction(inlineBlock: () -> Unit, noinline noInlineBlock: () -> Unit) {
    inlineBlock()
    noInlineBlock()
}

fun main() {
    mixedFunction(
        { println("Inline block") },
        { println("Noinline block") }
    )
}
编译后代码分析

inlineBlock 会被内联展开,而 noInlineBlock 不会。编译后的代码大致如下:

public class Main {
    private static final class NoInlineBlock implements Function0<Unit> {
        public Unit invoke() {
            System.out.println("Noinline block");
            return Unit.INSTANCE;
        }
    }

    public static void main(String[] args) {
        System.out.println("Inline block");
        NoInlineBlock noInlineBlock = new NoInlineBlock();
        noInlineBlock.invoke();
    }
}

inlineBlock 被内联到调用处,而 noInlineBlock 被封装成一个实现了 Function0 接口的类,通过创建对象并调用 invoke 方法来执行。

3. crossinline 关键字

Kotlin 代码示例
inline fun crossInlineFunction(crossinline block: () -> Unit) {
    val wrapper = {
        block()
    }
    wrapper()
}

fun main() {
    crossInlineFunction {
        println("Crossinline block")
    }
}
编译后代码分析

crossinline 保证了 Lambda 表达式不会有非局部返回,但仍然会被内联。编译后的代码大致如下:

public class Main {
    public static void main(String[] args) {
        final class Wrapper implements Function0<Unit> {
            public Unit invoke() {
                System.out.println("Crossinline block");
                return Unit.INSTANCE;
            }
        }
        Wrapper wrapper = new Wrapper();
        wrapper.invoke();
    }
}

block 被内联到 wrapper 中,同时由于 crossinline 的存在,避免了非局部返回的问题。

总结来说,inline 关键字使函数体在调用处展开,noinline 阻止特定函数参数内联,crossinline 允许内联的同时限制非局部返回,这些关键字在编译后的代码中体现了不同的处理方式。

相关文章:

  • 西门子G120扭矩控制
  • 系统设计类问题回答模板
  • 平芯微PW5012应用电路
  • emWin自定义键盘布局
  • 实验一、Linux环境下实现进度条小程序:深入解析核心实现与关键技术细节
  • 英伟达有哪些支持AI绘画的 工程
  • VMWare虚拟机磁盘扩容
  • Dify 0.15.3 输入变量无法被重新赋值问题-解决方法
  • 用selenium+ChromeDriver豆瓣电影 肖申克的救赎 短评爬取(pycharm 爬虫)
  • 基于CNN-LSTM联合网络的主瓣干扰辨识
  • 三个HTTP请求参数注解@RequestHeader、@RequestParam和@RequestBody的使用对比
  • 神聖的綫性代數速成例題21. 酉空間的基本概念、酉變換與酉矩陣的性質及應用、矩陣的奇異值分解及其應用
  • Eclipse Debug 调试
  • 【C++】STL库_list 的模拟实现
  • 三个print优雅打印datetime模块的“时间密码”
  • 笔试专题(二)
  • Rust函数、条件语句、循环
  • 动态查找表
  • 1.2 编译器结构
  • 把 ASP.NET Core 服务(BigDogServer)部署到 Linux 并作为服务运行
  • 葡萄牙、西班牙突发大范围停电,交通和通信服务受到严重影响
  • 深圳宝安区一宗涉宅用地中止出让,起始总价86.27亿元
  • 国务院任免国家工作人员:饶权任国家文物局局长
  • 当隐身13年的北小京决定公开身份 ,专业戏剧评论依然稀缺
  • 学校食堂饭菜有蛆?举报人遭值班人员辱骂?四川苍溪县教育局回应
  • 上海经信委:将推动整车企业转型,加强智能驾驶大模型等创新应用