我们知道 inline 函数的作用是可以在调用处替换为函数体实现,可以减少函数调用栈的使用,从而提升效率,本文会一起看看跟 inline 一起配合使用的几个关键字
0x00 inline + reified
在Kotlin中经常会看到一些内联函数是配合 reified 关键字使用
- 保留运行时的类型
- 原理是在调用处将范型替换为实际类型
kotlin
inline fun <T> checkType(obj: Any) {
if (obj is T) { // ❌ 这里会编译出错!
println("${obj} 是 ${T::class.simpleName} 类型")
}
}
kotlin
// 添加 reified 关键字(必须配合 inline 使用)
inline fun <reified T> checkType(obj: Any) {
if (obj is T) { // ✅ 现在可以了!
println("${obj} 是 ${T::class.simpleName} 类型")
}
}
// 使用示例
checkType<String>("Hello") // 输出:Hello 是 String 类型
checkType<Int>("Text") // 无输出,类型不匹配
简化Activity启动(无需传递Class参数)
kotlin
// 使用 reified 的优雅方式
inline fun <reified T : Activity> Context.startActivity() {
val intent = Intent(this, T::class.java) // 直接访问泛型类型的Class
startActivity(intent)
}
// 调用 - 类型清晰,无需::class.java
startActivity<DetailActivity>()
Retrofit + reified 简化API响应处理
kotlin
// 传统方式:需要传递Type
apiService.getUser().enqueue(object : Callback<User> {
override fun onResponse(call: Call<User>, response: Response<User>) {
// 处理响应
}
})
// 使用 reified 的扩展函数
inline fun <reified T> Call<T>.enqueueSimplified(
crossinline onSuccess: (T) -> Unit,
crossinline onError: (Throwable) -> Unit
) {
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
onSuccess(response.body()!!)
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
onError(t)
}
})
}
// 调用更加简洁
apiService.getUser().enqueueSimplified(
onSuccess = { user -> showUser(user) },
onError = { error -> showError(error) }
)
0x01 noinline:阻止内联
为什么需要它?当一个 Lambda 参数需要被存储 、传递 给其他非内联函数,或在非内联上下文中调用 时,就必须使用 noinline.
kotlin
// 示例:需要存储 Lambda
inline fun doSomething(
crossinline onStart: () -> Unit, // 这个会被内联
noinline onComplete: () -> Unit // 这个不会被内联
) {
// 1. onStart 可以直接调用(内联)
onStart()
// 2. onComplete 需要被存储或传递
val completionCallback = onComplete // ✅ 可以存储,因为它是 noinline
runLater(completionCallback) // ✅ 可以传递给普通函数
// 3. 尝试存储 onStart 会报错
// val startCallback = onStart // ❌ 错误:不能存储 crossinline lambda
}
// 一个普通(非内联)函数
fun runLater(callback: () -> Unit) {
// 稍后执行...
}·
关键特性:
- 变为普通函数对象,有内存开销
- 可以传递给其他非内联函数
- 可以存储在变量或属性中
- 不支持非局部返回(因为它已经不是内联的了)
0x02 crossinline:禁止非局部返回
作用 :允许 Lambda 被内联,但禁止在 Lambda 内部使用非局部返回 (即直接 return)。
为什么需要它?
当 Lambda 参数在另一个执行上下文中被调用时(如嵌套函数、另一个 Lambda),直接 return 会变得语义模糊,因此需要禁止
kotlin
// 示例:Lambda 在嵌套上下文中执行
inline fun runInBackground(crossinline task: () -> Unit) {
// 将 task 传递给另一个执行上下文
Thread {
task() // 这里 task 是在新线程中执行,不是从 runInBackground 返回
}.start()
}
fun testFunction() {
runInBackground {
println("在后台执行")
// return // ❌ 如果允许,这个 return 是要从 testFunction 返回,还是从 Lambda 返回?
// 编译器禁止这种模糊的语义,必须使用:
return@runInBackground // ✅ 明确表示从 Lambda 返回
}
println("这行会被执行")
}
典型应用场景:
kotlin
// Android 中的 View.post 就是一个典型例子
public inline fun View.post(crossinline action: () -> Unit) {
val runnable = Runnable { action() } // action 在 Runnable 中执行
handler.post(runnable)
}
// 使用
view.post {
updateUI()
// 不能直接 return,必须用 return@post
if (condition) return@post // ✅ 局部返回
}
场景:结合使用多个修饰符
kotlin
inline fun processData(
data: String,
noinline validator: (String) -> Boolean, // 需要传递给普通函数
crossinline onSuccess: (String) -> Unit, // 在回调中执行,禁止非局部返回
onError: (Exception) -> Unit // 默认内联,允许非局部返回
) {
// validator 被传递给普通函数
if (!validateInput(data, validator)) {
onError(IllegalArgumentException("无效数据"))
return
}
// onSuccess 在异步回调中执行
doAsyncWork(data) { result ->
onSuccess(result) // 这里禁止非局部返回
}
}
fun validateInput(input: String, validator: (String) -> Boolean): Boolean {
return validator(input) // 普通函数接收 noinline lambda
}
0x03 核心总结
noinline是"功能开关":关闭内联,换取存储/传递能力crossinline是"安全限制":保持内联,但禁止模糊的返回语义- 默认行为是最灵活的:既内联又允许非局部返回,但限制最多