0Pricing
Kotlin Academy · 课时

noinline 与 crossinline 修饰符

控制 inline 函数中特定 Lambda 参数的内联行为。

noinline 与 crossinline 修饰符 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。

inline 要解决并引入的问题

函数为 inline 时,其所有匿名函数参数默认都会被内联。有时您需要指定某个匿名函数不被内联,例如需要将它存储起来,或将它传递给另一个非内联函数。

noinline:将一个匿名函数保留为对象

在指定的匿名函数参数前加上 noinline,即可选择不对其进行内联,同时保留其余参数的内联行为。

inline fun doWork(
    action: () -> Unit,
    noinline callback: () -> Unit   // stored, not inlined
) {
    action()                        // inlined at call site
    scheduleCallback(callback)      // passed as object — valid
}

必须使用 noinline 的情况

在以下情况下必须使用 noinline:

  • 匿名函数存储在变量或字段中
  • 匿名函数被传递给需要函数类型的另一个函数
  • 匿名函数从内联函数中返回

crossinline:禁止非局部返回

当内联匿名函数将在不同的执行上下文中调用(例如在另一个匿名函数内部或另一个线程中)时,可以使用 crossinline。它会告诉编译器:内联这个匿名函数,但不允许其中出现非局部返回。

inline fun runAsync(crossinline block: () -> Unit) {
    Thread {
        block()   // block is inlined but cannot use non-local return
    }.start()
}

非局部返回为何在此处有风险

如果 block 可以使用非局部 return,它就会尝试从调用 runAsync 的函数中返回。但在线程运行时,该函数可能已经返回,从而导致未定义行为。crossinline 会在编译时阻止这种情况。

组合使用 noinline 和 crossinline

一个内联函数可以混合使用普通参数、noinline 参数和 crossinline 参数:

inline fun orchestrate(
    crossinline setup: () -> Unit,
    action: () -> Unit,
    noinline teardown: () -> Unit
) {
    Thread { setup() }.start()
    action()
    register(teardown)
}

没有 crossinline 时的编译器错误

如果将内联匿名函数传递到匿名函数上下文中,却没有使用 crossinline,编译器会发出以下错误:“无法在此处内联代码块:它可能包含非局部返回。请添加 crossinline 修饰符。”

标准库中的使用

标准库在 Sequence { } 等函数以及某些协程构建器中使用 crossinline,确保用户提供的匿名函数能够在不同上下文中安全运行。

noinline 不会破坏 inline

将一个参数标记为 noinline 不会关闭整个函数的内联。函数体和其他所有匿名函数参数仍会被内联。只有标记为 noinline 的匿名函数会保留其对象身份。

性能注意事项

noinline 会让该参数承担通常的匿名函数分配开销。crossinline 仍然会进行内联,唯一的限制是不允许非局部返回。这两个修饰符都不会影响其他参数的内联。

总结表

修饰符总结:

  • 没有修饰符 → 匿名函数完全内联,允许非局部返回
  • noinline → 匿名函数保留为对象,可以存储或传递
  • crossinline → 匿名函数会被内联,但禁止非局部返回

快速检查

什么时候必须在 inline 函数的匿名函数参数上使用 noinline?

回顾:noinline 与 crossinline

关键要点:

  • noinline:在一个原本内联的函数中,将一个匿名函数保留为对象
  • crossinline:内联匿名函数,但禁止非局部返回,以便安全地跨上下文使用
  • 这两个修饰符都分别应用于参数,而不是整个函数

常见问题解答

「noinline 与 crossinline 修饰符」课时是免费的吗?

是的 — 「noinline 与 crossinline 修饰符」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。

「noinline 与 crossinline 修饰符」这节课中我会学到什么?

控制 inline 函数中特定 Lambda 参数的内联行为。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Kotlin Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「noinline 与 crossinline 修饰符」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Kotlin Academy 课中编写并运行代码吗?

能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. inline 函数:消除 Lambda 开销
  2. noinline 与 crossinline 修饰符
  3. reified 类型参数:在运行时访问 T
  4. 实用的 Reified 模式:解析、DI 与序列化
← 返回 Kotlin Academy