前言:被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很好用!