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

1. inline、noinline、crossinline 的作用

在 Kotlin 里,inlinenoinlinecrossinline 这几个关键字和高阶函数紧密相关,它们能够对高阶函数的行为进行优化和控制。本文接下来会详细介绍它们的作用和原理。

1.1 inline 关键字

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

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

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

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

1.2 noinline 关键字

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

1.2.1 示例代码
kotlin 复制代码
// 定义一个内联高阶函数,包含一个 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.") }
    )
}
1.2.2 代码解释

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

1.3 crossinline 关键字

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

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

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

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

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

2.对应编译后的代码是怎样的 ?

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

2.1 inline 关键字

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

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

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

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.2 noinline 关键字

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

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

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

java 复制代码
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 方法来执行。

2.3 crossinline 关键字

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

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

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

java 复制代码
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 允许内联的同时限制非局部返回,这些关键字在编译后的代码中体现了不同的处理方式。

相关推荐
pengyu几秒前
系统化掌握Dart网络编程之Dio(二):责任链模式篇
android·flutter·dart
水w5 分钟前
【Android Studio】如何卸载干净(详细步骤)
android·开发语言·android studio·activity
weixin_307779135 分钟前
判断HiveQL语句为建表语句的识别函数
开发语言·数据仓库·hive·c#
一顿操作猛如虎,啥也不是!10 分钟前
JAVA-Spring Boot多线程
开发语言·python
亦是远方13 分钟前
2025华为软件精英挑战赛2600w思路分享
android·java·华为
v维焓19 分钟前
C++(思维导图更新)
开发语言·c++·算法
jiet_h20 分钟前
深入解析KSP(Kotlin Symbol Processing):现代Android开发的新利器
android·开发语言·kotlin
清晨細雨21 分钟前
UniApp集成极光推送详细教程
android·ios·uni-app·极光推送
_未知_开摆22 分钟前
uniapp APP端在线升级(简版)
开发语言·前端·javascript·vue.js·uni-app
花月C27 分钟前
Spring IOC:容器管理与依赖注入秘籍
java·开发语言·rpc