前言:被Elon Musk圈粉后,以为他必定是我一生的偶像,他正作着一些那些求之不得,人类最浪漫最伟大的事情.bash
首先更正下我在 Kotlin 进阶教程(一)文末分析apply源码的一个错误:闭包
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
复制代码
这个内联函数,是一个关于T的扩展函数,其入参block的写法,看上去好像不太好理解;T.()是什么玩意?最初我也把它理解成了T的扩展函数,这个理解是不对的,更正一下.虽然它的样子很像扩展函数,但它并非;它是一个带有接收者的函数字面值. 接受者的函数字面值,怎么理解呢; eg: 匿名函数语法容许直接指定函数字面值的接收者类型 因此能够以下定义一个匿名函数sumapp
val sum = fun Int.(another: Int): Int = this + another
复制代码
this表明调用者自己,那么,我就能够这样调用sum; eg:函数
val sum = 2.sum(3).sum(4)
println("$sum")
复制代码
输出9; 显而易见,咱们可让调用者也成为入参的一部分,this表示; 因此apply函数能够轻松实现链式调用;工具
观察以下代码post
val map = mapOf<Int, String>(1 to "one", 2 to "two")
复制代码
能够看到1 to "one" 很方便映射了key-value 点进去看一下源码性能
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
复制代码
能够看到这个to函数是一个A的扩展函数,入参是B,因此我猜测 to 函数还能够这样调用 1.to("one")
; 而且有infix修饰,infix即中缀函数的修饰符; 很显然1.to("one"),
和1 to one
比较,后者更加简洁优雅; 对于中缀函数,它只能有一个参数,切有infix修饰;ui
了解了中缀函数,那么咱们能够利用它发挥你的想象力,创造一些十分优雅的API .好比咱们计算某个天数前的时间戳能够这么写:this
val yesterday = 1 days ago
val theDayBeforeYesterday= 2 days ago
复制代码
代码看上就想在写英文语句同样;spa
object ago
infix fun Int.days(ago: ago):Long {
....//计算时间
return time
}
复制代码
内联函数用inline修饰 在使用高阶函数时会带来一些运行时的效率损失:每个函数都是一个对象,而且会获得一个闭包; 在(一)中我提过inline函数编译器会将函数编译成执行的代码块,从而避免了函数频繁的压栈和出栈. 咱们能够看到Kotlin的源码中,尤为是标准库,大量使用了内联函数,内联函数会是性能有所提高; 因此在咱们开发中,一些工具性函数,推荐liline函数;
lambda表达式中禁止裸用return进行函数返回,可是若是lambda 表达式传给的函数是内联的,该 return也能够内联,因此它是容许的:
fun foo() {
lambda { _: Int, _: Int ->
println("内部已返回")
return //方法内联,因此这里是OK的
println("内部未返回")
}
println("lambda局部返回,后续代码执行")
}
inline fun lambda( o: (x: Int, y: Int) -> Unit) {
o.invoke(3, 4)
}
复制代码
执行foo(),输出:内部已返回; 能够看到这里的return非局部返回
可是若是传入的lambda是内联的,可是又不容许其非局部控制流,那么须要用crossinline修饰 eg:
fun foo() {
lambda { _: Int, _: Int ->
println("内部已返回")
// return //方法内联,可是crossinlie修饰,因此这里是不容许的,
return@lambda //标签是容许的
println("内部未返回")
}
println("lambda局部返回,后续代码执行")
}
inline fun lambda( crossinline o: (x: Int, y: Int) -> Unit) {
o.invoke(3, 4)
}
复制代码
执行foo(),输出:
内部已返回
lambda局部返回,后续代码执行
有理解错误的请指正!!! 重要的事情说三遍: kotlin很好用!
kotlin很好用!
kotlin很好用!