Kotlin 内联函数与block.invoke()的妙用

在 Kotlin 开发中,我们经常使用 block.invoke() 来调用函数类型的变量,但你是否知道 block() 其实是完全一样的?为什么很多人更习惯 block.invoke()?它和 Kotlin 的内联函数 inline 又有什么关系?今天,我们就从 block.invoke() 讲起,深入解析 Kotlin 内联函数的用法和优点,并探讨 block.invoke()block() 之间的细节差异。


1. block.invoke() 的日常使用

我们经常会在 Kotlin 代码中看到类似这样的写法:

kotlin 复制代码
fun doSomething(block: () -> Unit) {
    println("Before block")
    block.invoke()  // 执行 block 代码块
    println("After block")
}

fun main() {
    doSomething {
        println("Inside block")
    }
}

执行结果:

复制代码
Before block
Inside block
After block

doSomething 这个函数里,block.invoke() 的作用就是执行 block 这个 Lambda 代码块。


2. inline 内联函数的优化

在 Kotlin 中,inline 关键字可以让 高阶函数(即参数是函数的函数)在编译时直接展开,提高运行时性能。

✅ 内联优化前

来看一个普通的高阶函数:

kotlin 复制代码
fun doSomething(block: () -> Unit) {
    println("Before block")
    block.invoke()
    println("After block")
}

在 JVM 上,调用 doSomething 时,block 作为 一个对象 传递给 doSomething,然后 block.invoke() 在运行时执行这个对象的 invoke() 方法。这种方式会:

  • 多创建一个 Lambda 对象
  • 多一次方法调用开销

✅ 内联优化后

如果我们给 doSomething 加上 inline

kotlin 复制代码
inline fun doSomething(block: () -> Unit) {
    println("Before block")
    block.invoke()
    println("After block")
}

那么 编译器会直接把 doSomething 里的 block.invoke() 展开为

kotlin 复制代码
fun main() {
    println("Before block")
    println("Inside block")  // block.invoke() 直接替换为代码块
    println("After block")
}

这样:

  • 避免了 Lambda 对象的创建
  • 减少了函数调用的开销
  • 提升了运行效率

因此,inline 关键字在高阶函数中非常有用,特别是当 block 频繁调用时,优化效果更明显!


3. block.invoke() 其实和 block() 是一样的

很多人写习惯了 block.invoke(),但其实你完全可以写成 block()

kotlin 复制代码
fun doSomething(block: () -> Unit) {
    println("Before block")
    block()  // 和 block.invoke() 是一样的!
    println("After block")
}

block() 其实是 block.invoke() 的语法糖,它们的作用完全相同:

kotlin 复制代码
block.invoke()  // 明确调用 invoke 方法
block()         // 语法糖,等价于上面那行

为什么很多人更喜欢 block.invoke()

原因可能是:

  1. Kotlin 允许显式调用 invoke() ,而且大家在 IDE 提示下会看到 invoke(),就容易跟着写。

  2. 在可空情况下,大家经常写 block?.invoke()

    kotlin 复制代码
    fun doSomething(block: (() -> Unit)?) {
        block?.invoke()  // 这里不能写 block()?,否则编译错误
    }

    因为 block?.() 这种语法在 Kotlin 里不被支持,所以 block?.invoke() 变成了大家的默认写法。


4. 什么时候用 block(),什么时候用 block?.invoke()

写法 适用场景 说明
block() block 一定不为空 ✅ 推荐,语法最简洁
block.invoke() block 一定不为空 ✅ 功能相同,但写法稍长
block?.invoke() block 可能为空 推荐 ,防止 NullPointerException

最佳实践:

  • 如果 block 一定不为空 ,建议直接写 block(),更简洁
  • 如果 block 可能为空 ,用 block?.invoke() 避免 NullPointerException

5. 总结

  1. block.invoke()block() 完全等价 ,只是 block() 更简洁。
  2. inline 关键字能让高阶函数更高效,避免 Lambda 对象创建,减少调用开销。
  3. 如果 block 可能为空,就用 block?.invoke(),防止 NullPointerException
  4. inline 适用于频繁调用的高阶函数,提高执行效率!

以后写代码时,你可以直接写 block(),除非 block 可能为空,那就用 block?.invoke()!😃


这篇博客的核心目标是让大家 理解 block.invoke() 的用法 ,以及 内联函数 inline 如何优化高阶函数,希望能帮助你写出更优雅的 Kotlin 代码!如果你觉得有收获,欢迎点赞、收藏或转发给你的同事!🚀

相关推荐
yangzhi_emo15 分钟前
ES6笔记2
开发语言·前端·javascript
花花鱼1 小时前
android studio 设置让开发更加的方便,比如可以查看变量的类型,参数的名称等等
android·ide·android studio
emplace_back1 小时前
C# 集合表达式和展开运算符 (..) 详解
开发语言·windows·c#
jz_ddk1 小时前
[学习] C语言数学库函数背后的故事:`double erf(double x)`
c语言·开发语言·学习
萧曵 丶1 小时前
Rust 所有权系统:深入浅出指南
开发语言·后端·rust
xiaolang_8616_wjl2 小时前
c++文字游戏_闯关打怪2.0(开源)
开发语言·c++·开源
收破烂的小熊猫~2 小时前
《Java修仙传:从凡胎到码帝》第四章:设计模式破万法
java·开发语言·设计模式
nananaij2 小时前
【Python进阶篇 面向对象程序设计(3) 继承】
开发语言·python·神经网络·pycharm
alexhilton2 小时前
为什么你的App总是忘记所有事情
android·kotlin·android jetpack