ZetCode

Kotlin crossinline 关键字

最后修改于 2025 年 4 月 19 日

Kotlin 的内联函数通过内联 lambda 表达式来优化高阶函数。crossinline 修饰符限制从传递给内联函数的 lambda 中进行非局部返回。本教程将通过实际示例深入探讨 crossinline。

基本定义

crossinline 关键字标记内联函数中的 lambda 参数。它阻止从这些 lambda 中进行非局部返回,同时仍然允许内联。这确保了在局部对象或嵌套函数等上下文中的正确控制流。

crossinline 的基本用法

此示例展示了 crossinline 的最简单用法。我们定义了一个内联函数,其中包含一个 crossinline lambda 参数,以防止非局部返回。

BasicCrossinline.kt
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 中的控制流。

InlineComparison.kt
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 至关重要。此示例演示了它在局部对象上下文中的用法。

LocalObjectExample.kt
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 如何影响循环和条件语句中的返回。

ControlStructures.kt
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。此示例模仿这种用法以展示实际应用。

LibraryStyle.kt
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 参数。此示例展示了它们在同一函数中的交互方式。

MultipleLambdas.kt
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 在标准库中的使用。

ResourceManagement.kt
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 的最佳实践

来源

Kotlin 内联函数文档

本教程深入介绍了 Kotlin 的 crossinline 关键字,展示了它在内联函数中的作用。我们探讨了各种场景,包括局部对象、控制结构和资源管理。正确使用 crossinline 有助于保持可预测的控制流,同时保留内联的好处。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有多年的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我写了 1400 多篇文章和 8 本电子书。我拥有超过八年的编程教学经验。

列出 所有 Kotlin 教程