inline

Posted on By ᵇᵒ

inline

  • 用在函数上,告诉编译器在调用处展开函数体,而不是生成函数调用。常用于高阶函数(函数参数),可以减少 lambda 对象的创建 和 虚拟调用开销。
  • 在高阶函数中使用 inline,支持 lambda(不加 crossinline/noinline)非局部返回(non-local return)。
inline fun doSomething(action: () -> Unit) {
    println("Before action")
    action()  // lambda 会直接展开到这里
    println("After action")
}

fun main() {
    doSomething {
        println("Hello")
        return   // 非局部返回:直接从 main 返回
    }
    println("This line is unreachable") // 因为 lambda 非局部返回
}

inline 是针对函数本身和它的 lambda 参数一起展开的,而不仅仅是 lambda 参数。当然主要的收益还是 lambda 参数也会被展开,所以当 inline 修饰的函数本身不带有 lambda 参数时,IDE 会告警:

Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of function types.

crossinline

用在 inline 函数的 lambda 参数上,禁止非局部返回(non-local return),lambda 允许被内联。
为什么需要 crossinline? 如果 lambda 被内联,但不能保证 lambda 调用的上下文允许非局部返回,就需要加 crossinline 禁止 lambda 内部直接从调用函数返回。

inline fun doSomethingCross(crossinline action: () -> Unit) {
    val runnable = Runnable {
        action() // lambda 会展开到这里,但是不能使用非局部 return
    }
    runnable.run()
}

fun main() {
    doSomethingCross {
        println("Hello")
        // return // ❌ 编译错误,crossinline 禁止非局部返回
    }
}

noinline

用在 inline 函数的 lambda 参数上,告诉编译器不要内联这个 lambda,同时禁止非局部返回(non-local return)。适合:

  • lambda 参数需要 保存为变量 或 传递给其他函数
  • 避免 lambda 被内联导致不必要的非局部返回限制
inline fun doSomethingInline(noinline action: () -> Unit) {
    println("Before action")
    action() // lambda 不会展开到这里,也不能使用非局部 return
    println("After action")
}

fun main() {
    // 可以安全保存
    val savedAction = { 
        println("Saved action") 
        // return // ❌ 编译错误,noinline 禁止非局部返回
    }
    doSomethingInline(savedAction)
}