inline/noinline/crossinline/reified
内联,这个概念无需多说.
kotlin中使用高阶函数在运行时会有一些性能损失:每一个函数都是一个对象,并且都会捕获一个闭包(哪些在函数体内可以访问到的变量),对函数对象和类进行内存分配,和虚拟调用都会引入一些运行时间开销.
因此kotlin中经常用inline来优化lambda表达式,比如我们常用的let
,apply
方法:
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
不过内联可能会导致生成的字节码增加,尽量不要将过大的函数进行内联.
禁用内联/noinline
有时候内联方法中传入了lambda表达式作为参数,但是又不想这个参数lambda内联,可以使用noinline
禁用内联:
inline fun <reified T : Task> Project.task(noinline configuration: T.() -> Unit) = tasks.registering(T::class, configuration)
对于那些并没有什么益处的内联,编译器会产生一个警告
非局部返回
kotlin中我们只能对具名或者匿名函数使用正常的return来退出,在lambda表达式中则必须使用一个标签来return.
有一种情况例外,就是lambda是内联的,这个时候可以正常return(因为lambda的return也内联了).
这么说可能不清楚,来个例子吧:
fun funWithoutInline(block:() -> Unit){
block()
}
inline fun funInline(block: () -> Unit){
block()
}
fun test():Boolean{
// 只能使用这种方式,不能直接return
funWithoutInline {
return@funWithoutInline
}
funInline {
return true
}
funInline {
return@funInline
}
return false
}
Break 和continue 在内联的lambda表达式暂时不可用.
内联lambda嵌套问题
对于一般嵌套的lambda没什么影响,内联的lambda则需要使用crossinline
进行修饰:
inline fun embedInlineFun(crossinline block:()->Unit){
Runnable {
// 如果不加crossinline会报错
block()
}.run()
}
fun embedFun(block:()->Unit){
Runnable {
block()
}.run()
}
具体化的类型参数
其实就是inline
+ reified
+ 泛型,最典型的例子就是下面这个:
inline fun <reified T: Activity> Context.startActivity(){
startActivity(Intent(this,T::class.java))
}
这个修饰符的作用就是在方法内部可以使用具体化的类型参数.
reified 修饰符必须与 inline搭配使用
内联属性
不多说,看代码:
val foo: Foo
inline get() = Foo()
var bar: Bar
get() = ……
inline set(v) { …… }
inline var bar: Bar
get() = ……
set(v) { …… }