内联函数 (Inline Functions)
使用高阶函数会导致一些运行时惩罚:每个函数都是对象,且会捕获闭包。频繁调用(如在循环中)会带来显著的内存与 CPU 开销。 内联 (Inline) 是 Kotlin 解决此性能问题的杀手锏。
内联原理:代码展开
当你将函数标记为 inline,编译器会将其 函数体 及其 Lambda 参数的代码 直接复制粘贴到调用处。
kotlin
inline fun runOp(block: () -> Unit) {
println("Start")
block()
println("End")
}
fun main() {
runOp { println("Action") }
}kotlin
fun main() {
// 编译器直接将 runOp 的内容搬过来了
println("Start")
println("Action") // Lambda 内部的代码也被铺平了
println("End")
// 结果:没有任何多余的对象创建和函数调用开销!
}泛型具体化 (Reified)
由于 JVM 的 类型擦除 (Type Erasure),通常无法在运行时获取泛型 T 的类型。 但因为内联函数会被“展开”,编译器知道实际传入的类型是什么。配合 reified 关键字,我们可以直接访问类型信息。
实战:Android 扩展
不使用 Reified:
kotlin
fun <T : Activity> startActivity(context: Context, clazz: Class<T>) {
context.startActivity(Intent(context, clazz))
}
// 调用丑陋:
startActivity(context, DetailActivity::class.java)使用 Reified:
kotlin
inline fun <reified T : Activity> Context.startActivity() {
// T::class 直接可用!
startActivity(Intent(this, T::class.java))
}
// 调用优雅:
context.startActivity<DetailActivity>()非本地返回 (Non-local Returns)
在普通 Lambda 中,你不能直接使用 naked return(必须用 return@label)。但在内联函数的 Lambda 中,由于代码被平铺到外部,你可以直接使用 return 结束 外部函数。
kotlin
fun hasZeros(list: List<Int>): Boolean {
list.forEach { // forEach 是 inline 的
if (it == 0) return true // ✅ 直接结束 hasZeros 函数
}
return false
}控制内联行为
noinline
如果内联函数有多个 Lambda 参数,你可以选择只内联其中一部分。标记为 noinline 的参数会被保留为普通函数对象(以便存储或传递)。
kotlin
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ... }crossinline
如果你需要在内联函数中,将 Lambda 传递给另一个 非内联 上下文(比如 runOnUiThreads { ... }),编译器会报错,防止你通过该 Lambda 意外结束外部函数。 标记 crossinline 承诺:此 Lambda 一定不会执行 return(非本地返回)。
kotlin
inline fun executeAsync(crossinline body: () -> Unit) {
// 假如没有 crossinline,这里会报错,因为 body 可能包含 return,
// 而 executeAsync 内联后,return 会试图结束调用者,这在异步线程是不可能的。
thread { body() }
}限制与建议
访问限制
public 的内联函数不能访问 private 或 internal 的成员。这是因为内联代码会被复制到使用者的代码中,如果不受限,就会破坏封装性。
什么时候不该用 Inline?
- 函数体巨大:内联会导致调用处代码膨胀 (Code Bloat)。
- 不接收 Lambda 参数:没有 Lambda 参数的函数内联意义不大(JIT 编译器本身就在做普通内联优化)。