Kotlin crossinline 关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的内联函数通过内联 lambda 表达式来优化高阶函数。crossinline
修饰符限制从传递给内联函数的 lambda 中进行非局部返回。本教程将通过实际示例深入探讨 crossinline。
基本定义
crossinline
关键字标记内联函数中的 lambda 参数。它阻止从这些 lambda 中进行非局部返回,同时仍然允许内联。这确保了在局部对象或嵌套函数等上下文中的正确控制流。
crossinline 的基本用法
此示例展示了 crossinline 的最简单用法。我们定义了一个内联函数,其中包含一个 crossinline lambda 参数,以防止非局部返回。
package com.zetcode inline fun executeCrossinline(crossinline action: () -> Unit) { action() } fun main() { executeCrossinline { println("Action executed") // return // This would cause a compilation error } }
executeCrossinline
函数接受一个 crossinline lambda。注释掉的 return 语句会引发错误,因为 crossinline 阻止非局部返回。该函数仍然会被内联以提高性能。
crossinline 与常规内联
此示例对比了常规内联函数和 crossinline 变体。它展示了 crossinline 如何影响 lambda 中的控制流。
package com.zetcode inline fun regularInline(action: () -> Unit) { action() } inline fun withCrossinline(crossinline action: () -> Unit) { action() } fun main() { regularInline { println("Regular inline") return // Allowed: non-local return } withCrossinline { println("Crossinline") // return // Compilation error: non-local return not allowed } }
regularInline
函数允许从其 lambda 中进行非局部返回。withCrossinline
函数由于 crossinline 修饰符而禁止这样做。这种区别对于控制流管理至关重要。
crossinline 在局部对象中
当将 lambda 传递给局部对象或嵌套函数时,crossinline 至关重要。此示例演示了它在局部对象上下文中的用法。
package com.zetcode inline fun runInObject(crossinline action: () -> Unit) { val obj = object { fun execute() { action() } } obj.execute() } fun main() { runInObject { println("Executing in local object") // return // Would cause compilation error } }
在这里,lambda 被传递给局部对象的方法。如果没有 crossinline,非局部返回将是有问题的。crossinline 修饰符确保在局部对象上下文中的正确控制流。
crossinline 与控制结构
此示例展示了 crossinline 与控制结构一起使用。它演示了 crossinline 如何影响循环和条件语句中的返回。
package com.zetcode inline fun processItems( items: List<Int>, crossinline processor: (Int) -> Unit ) { for (item in items) { if (item < 0) { processor(item) // return // Not allowed here with crossinline } } } fun main() { val numbers = listOf(1, -2, 3, -4) processItems(numbers) { println("Processing negative: $it") } }
processItems
函数为其处理器 lambda 使用 crossinline。虽然允许局部返回,但禁止非局部返回。这在循环结构中保持了可预测的控制流。
crossinline 在库函数中
许多 Kotlin 标准库函数使用 crossinline。此示例模仿这种用法以展示实际应用。
package com.zetcode inline fun <T> T.applyCrossinline( crossinline block: T.() -> Unit ): T { val receiver = this receiver.block() return receiver } fun main() { val message = StringBuilder().applyCrossinline { append("Hello") append(", ") append("Kotlin") // return // Would cause compilation error } println(message.toString()) }
此 applyCrossinline
函数模仿 Kotlin 的标准 apply 函数,但带有 crossinline。它确保 lambda 不包含非局部返回,同时仍然被内联以提高性能。
crossinline 与多个 Lambda
函数可以同时具有常规 lambda 参数和 crossinline lambda 参数。此示例展示了它们在同一函数中的交互方式。
package com.zetcode inline fun handleEvents( regularAction: () -> Unit, crossinline safeAction: () -> Unit ) { regularAction() val handler = object { fun handle() { safeAction() } } handler.handle() } fun main() { handleEvents( { println("Regular action"); return }, { println("Safe action") /* return not allowed */ } ) }
该函数有一个常规内联 lambda 和一个 crossinline lambda。常规 lambda 允许非局部返回,而 crossinline lambda 不允许。这种组合提供了在不同使用场景中的灵活性。
crossinline 在实际场景中
此示例演示了 crossinline 在资源管理场景中的实际用例,类似于 Kotlin 在标准库中的使用。
package com.zetcode inline fun <T : AutoCloseable, R> T.useCrossinline( crossinline block: (T) -> R ): R { try { return block(this) } finally { close() } } fun main() { val result = System.`in`.bufferedReader().useCrossinline { it.readLine() // return // Would cause compilation error } println("Read: $result") }
此 useCrossinline
函数模仿 Kotlin 的 use 函数,但带有 crossinline。它通过防止可能跳过 finally 块的非局部返回来确保正确的资源清理。lambda 仍然会被内联以提高性能。
crossinline 的最佳实践
- 根据需要使用:仅当非局部返回会在局部对象或嵌套函数中引起问题时,才应用 crossinline。
- 记录行为:明确记录函数何时使用 crossinline,以便为 lambda 作者设定正确的期望。
- 谨慎组合:仔细混合常规参数和 crossinline 参数以保持清晰的控制流。
- 考虑替代方案:对于复杂场景,请考虑使用非内联函数或不同的架构。
- 遵循库模式:研究标准库对 crossinline 的使用,以获取有效模式的指导。
来源
本教程深入介绍了 Kotlin 的 crossinline
关键字,展示了它在内联函数中的作用。我们探讨了各种场景,包括局部对象、控制结构和资源管理。正确使用 crossinline 有助于保持可预测的控制流,同时保留内联的好处。
作者
列出 所有 Kotlin 教程。