0%

Kotlin 内联

inline、noinline、crossline区别?

inline:编译时把inline函数的代码拷贝到调用处

noinline:修饰inline标记的函数的形参,不希望内联lambda

crossline:inline函数中的lambda表达式不允许返回到外部函数,只能返回到lambda表达式

inline作用

Java中没有函数的概念,Kotlin中的lambda表达式在Java中对应的是一个FunctionN的单个方法的接口类,创建一个lambda表达式相当于创建一个类。

inline可以修饰函数,inline修饰的函数的形参中有lambda表达式,编译时不会创建对应的FunctionN类,而是直接把lambda表达式代码拷贝到调用处,这样

  1. 在循环等高频使用一个函数的场景下,内联lambda表达式避免了频繁创建对象,不仅节约了内存,也避免了频繁的垃圾回收,减少系统卡顿
  2. 减少了函数调用层级,函数调用栈少了一层,减少了性能损耗

inline会造成什么问题?

  1. 调用处的代码变多,所以不能内联代码量过大的函数,只适用于内联代码量小的函数
  2. 我们可以在inline函数形参的 lambda 表达式 中调用return直接返回外部函数,可能会导致inline函数之后的代码无法执行;需要使用return@label的语法,返回到lambda开始执行的位置
  3. 内联后的lambda表达式已经不是对象了,所以无法作为参数传递、存储在字段中、作为返回值return,需要加noinline解决

noinline作用

修饰inline函数的形参中的lambda表达式,表示禁止该lambda表达式内联

noinline禁止lambda表达式内联的意义是什么?

内联后的lambda表达式已经不是对象了,所以无法作为对象使用,也就是无法对其进行参数传递、存储在字段中、作为返回值return,需要加noinline解决

crossinline作用

既想让内联函数形参中的 lambda 也被 inline,但是又不想让 lambda 对调用方的控制流程产生影响(lambda中return会影响),就用crossline

crossinline依然是内联的

直接在lambda表达式中返回外部函数的情况称为非局部返回。

crossinline修饰的lambda禁止了非局部返回

crossinline为什么要禁止非局部返回?不禁止会有什么问题?

内联函数形参中的lambda表达式可能会在另外一个调用栈中执行,例如:

1
2
3
4
5
6
inline fun f(crossinline body: () -> Unit) {
val f = object: Runnable {
override fun run() = body()
}
// ……
}

正常情况下内联的lambda允许非局部返回,返回的是内联函数调用处的函数,但是不在一个调用栈中,非局部返回就无法做到这样的返回,所以必须禁止,用crossinline来禁止非局部返回,但仍然保持内联的特性,把lambda表达式的代码展开铺平。

内联类

  • 内联函数,可以消除函数调用的开销。
  • 内联类,则是可以消除创建对象的开销。

用途:

  • 严格的类型别名
  • 任何你想得到的包装类(wrapper)

参考:Kotlin 1.3 前瞻之 Inline Class