Kotlin笔记-015内联函数

130 阅读2分钟

内联函数

内联函数通过与高阶函数配合,实现代码优化

inline fun action(run: () -> Unit) {
    println("Hello")
    run()
    println("World")
}

fun main() {
    // 使用 inline 后,创建 Lambda 表达式的开销,和调用 action 的开销都没有
    action {
        println("Kotlin")
    }
    // 使用内联后,上面action方法相当于以下代码
    println("Hello")
    println("Kotlin")
    println("World")
}

内联高阶函数的 return

fun main() {
    val ints: IntArray = intArrayOf(1, 2, 3, 4)
    ints.forEach {index ->
        if (index == 3) {
            // 跳出这一次内联函数调用;相当于 continue
            return@forEach
        }
        println("main $index")
    }
}

non-local return

inline fun nonLocalReturn(act:()->Unit){
    act.invoke()
}

fun main() {
    nonLocalReturn {
        // 从main函数返回
        return
    }
}

crossinline 禁止外部返回

inline fun nonLocalReturn(crossinline act:()->Unit){
    act.invoke()
}

fun main() {
    nonLocalReturn {
        // 使用crossinline后,禁止从main函数返回
        // return
    }
}

内联函数的限制

  • public/protected 的内联方法只能访问对应类的 public 成员
  • 内联函数的内联函数参数不能被存储(赋值给变量)
  • 内联函数的内联函数参数只能传递给其他内联函数

inline/noinline/crossinline 总结

// 函数也是对象,在高阶函数中,函数参数被调用时需要被创建
// 编译后的class文件中,高阶函数中的函数参数是作为对象被创建来调用的
// 使用 inline 有优化编译效果,函数体被直接内联到class文件中,不需要再创建对象
inline fun action(run: () -> Unit) {
    println("Hello")
    run()
    println("World")
}

// 使用 inline 后函数不能被当成对象使用,函数体被直接内联到class文件中
// 但是如果函数需要被当成对象使用,比如被当成返回值,此时就需要处理这个问题
// 使用 noinline 可以不被内联,保持函数可以被当成对象使用
inline fun action2(run: () -> Unit, noinline run2: () -> Unit): () -> Unit {
    run()
    return run2
}

// 因为 inline 函数中函数体被直接编译到 class 文件
// 在 inline 函数中的 return 会直接返回调用 inline 函数的上层函数
// 比如在 action 函数中使用 return ,会直接返回调用 action 函数的 main 函数
// 但如果 inline 函数中的函数类型参数,又被间接调用,则 inline 函数中的 return 无法直接返回调用 inline 函数的上层函数
// 使用 crossinline 关键字,允许函数类型参数被间接调用,但代价是不允许直接调用 return
fun func(run: () -> Unit) {
    run()
}

inline fun action3(crossinline run: () -> Unit) {
    func {
        run()
    }
}

fun main() {
    // 从 action 函数返回
    action {
        println("Kotlin")
        return@action
    }
    // 从 main 函数返回
    action {
        println("Kotlin")
        return
    }
    // 被 crossinline 修饰的参数,允许在 inline 函数中被间接调用
    // 但是不能在 Lambda 中直接使用 return;只能 return@action3
    action3 {
        println("Kotlin")
        return@action3
    }

    // 使用 inline 后,创建 Lambda 表达式的开销,和调用 action 的开销都没有
    action {
        println("Kotlin")
    }
    // 使用内联后,上面action方法相当于以下代码
    println("Hello")
    println("Kotlin")
    println("World")
}