距離上篇Kotlin文章,應該有差很少半年時間.沒別的緣由,由於,懶,並且,想產出一篇稍微質量好的博客好難. 最近在研究Python,因此最近也可能會更新一些Python的學習筆記.java
StandardKt.kotlin源碼位於kotlin-stdlib-common/kotlin包下; Kotlin的擴展函數有多爽,我應該不用再描述了吧~~; 若是對kotlin擴展函數概念不清的能夠找找我前面的文章;api
Kotlin提供了一個標準函數庫,開發過程當中使用十分頻繁,也十分方便,只能說我已經完全沒法適應java開發了= =.bash
下面咱們來探究一下這個標準庫的源碼.標準庫函數容易混淆,但源碼比較簡單,不要慌.app
標準庫的函數基本都是內聯函數 inline修飾.不知道啥是內聯函數的,翻翻我前面的文章吧.less
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
複製代碼
run函數在標準庫有兩個; 咱們直接看第二個擴展函數.入參是一個block函數,類型是一個T的擴展函數T.()->R,無參,返回值是R類型 ,也能夠傳入lambda表達式,記住,kotlin中萬物皆對象,因此函數也是個對象; 例子:函數
/**
* 取絕對值
*/
fun Int.pow2():Double{
return Math.pow(toDouble(),2.toDouble())
}
fun testFun(){
val pow2 = "I am Zen".length.run({pow2()}) //1
Log.d(TAG,"pow2:$pow2")
}
執行testFun(),輸出:pow2:64.0
在Kotlin中,若是參數是最後一個參數,{}能夠提到()以後,那麼上述1式子能夠演變==>
val pow2 = "I am Zen".length.run(){pow2()}
Koltin中又規定,若是參數是惟一一個參數,那麼()也能夠省略,1式子能夠演變==>
val pow2 = "I am Zen".length.run{pow2()}
一樣的,若是直接傳入lamda表達式,也是ok的,1式能夠這樣寫==>
val pow2 = "I am Zen".length.run{Math.pow(toDouble(),2.toDouble())}
複製代碼
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
複製代碼
同窗們,仔細觀察,let函數和run函數的區別 能夠看到,T.let 入參傳入的block函數,其參數是T,返回值依舊是R,block在內部調用時傳入T.this;學習
/**
* 取絕對值
*/
fun Int.pow2():Double{
return Math.pow(this.toDouble(),2.toDouble())
}
fun testFun(){
val pow2 = "I am Zen".length.let { Math.pow(it.toDouble(),2.toDouble())} //1
Log.d(TAG,"pow2:$pow2")
}
執行testFun(),輸出:pow2:64.0
仔細觀察這個例子,能夠看到它和run函數的區別在於,run傳入的block函數內部直接持有的是T的引用;而let是外部傳入的T的引用,在lamda中用默認用it表示;
複製代碼
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
複製代碼
with函數和上述兩個又很像,= =,咱們來仔細辨別一下,它又有什麼不一樣ui
fun testFun(){
val pow2 = with("I am Zen".length){
Math.pow(toDouble(),2.toDouble())
}
Log.d(TAG,"pow2:$pow2")
}
執行testFun(),輸出:pow2:64.0
with函數有兩個入參receiver:T,block函數,關於T的擴展函數,返回R
複製代碼
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
複製代碼
also函數和let函數的區別在於,also返回的自身,入參block函數,無返回值this
val also = "I am Zen".length.also {
Math.pow(it.toDouble(), 2.toDouble())
}
Log.d(TAG,"also:$also")
輸出:also:8
字符串"I am Zen".length爲8,對8執行also函數,內部持有外部傳入的T引用,用it表示,內部計算了it的二次冪,可是返回的仍是T自己,也便是8;因此,不難理解吧;和also函數相似的是apply函數.
複製代碼
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
複製代碼
apply函數十分經常使用,它能夠輕鬆實現java的鏈式調用,咱們不用再那麼麻煩寫build模式啦; 能夠看出apply函數和also函數很相識,不一樣的是,對於lamda內部,apply函數中直接持有T的引用,this能夠省略,因此能夠直接調用關於T的全部api,而also持有的是外部傳入的T的引用,用it表示,因此須要用it來調用關於T的全部apispa
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (predicate(this)) this else null
}
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (!predicate(this)) this else null
}
複製代碼
takeIf和takeUnless只是斷言相反 因此只講一下takeIf 這也是個十分實用的標準函數,傳入的predicate斷言函數,返回值Boolean,對於takeIf而言,符合條件則返回T,不然返回null,話很少說,直接看例子:
val age=17
val adultAge= age.takeIf {
it >= 18
}
Log.d(TAG,"isAdult or null:$adultAge")
輸出:isAdult or null:null
predicate函數斷言條件就是>=18;17執行takeIf,斷言失敗,返回null;
複製代碼
@kotlin.internal.InlineOnly
public inline fun repeat(times: Int, action: (Int) -> Unit) {
contract { callsInPlace(action) }
for (index in 0 until times) {
action(index)
}
}
複製代碼
這個標準函數能夠輕鬆實現循環任務;time是循環的次數,action函數指定具體循環的動做
repeat(5){
Log.d(TAG,"print:$it")
}
輸出:
print:0
print:1
print:2
print:3
print:4
複製代碼
對於java基礎者,Koltin是一門十分容易上手的語言,並且在使用了將近一年的時間後,我深深感到Kotlin給我解放的生產力.