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 代码!如果你觉得有收获,欢迎点赞、收藏或转发给你的同事!🚀

相关推荐
東隅已逝,桑榆非晚1 分钟前
新手入门指南:认识 C 语言文件操作(上)
c语言·开发语言·笔记
cany10003 分钟前
C++ -- 动态内存分配和释放(new/delete)
开发语言·c++
brycegao32113 分钟前
Vue3+Go 全栈项目上线阿里云|从 0 到 1 踩坑全纪录
开发语言·阿里云·golang
帅次14 分钟前
讯飞与腾讯云:Android 实时语音识别服务对比选择
android·ios·微信小程序·小程序·android studio·android runtime
ch.ju15 分钟前
Java Programming Chapter 4——cite
java·开发语言
优雅格子衫28 分钟前
uniapp 拍照相册选取后超级好用的裁剪组件,增加水印完全自定义
开发语言·前端·javascript·uni-app·vue
Vallelonga40 分钟前
Rust 中 unsafe 关键字的语义
开发语言·rust
AI砖家44 分钟前
前端 JavaScript 异步处理全方案详解:从回调到 Observable
开发语言·前端·javascript
思麟呀1 小时前
C++工业级日志项目(七)日志器核心
linux·开发语言·c++·windows
2401_873479401 小时前
如何用IP离线库批量清洗订单IP,自动标注省市区?
开发语言·网络·python