Kotlin StandardKt 標準庫源碼走一波

距離上篇Kotlin文章,應該有差很少半年時間.沒別的緣由,由於,懶,並且,想產出一篇稍微質量好的博客好難. 最近在研究Python,因此最近也可能會更新一些Python的學習筆記.java

StandardKt.kotlin源碼位於kotlin-stdlib-common/kotlin包下; Kotlin的擴展函數有多爽,我應該不用再描述了吧~~; 若是對kotlin擴展函數概念不清的能夠找找我前面的文章;api

Kotlin提供了一個標準函數庫,開發過程當中使用十分頻繁,也十分方便,只能說我已經完全沒法適應java開發了= =.bash

下面咱們來探究一下這個標準庫的源碼.標準庫函數容易混淆,但源碼比較簡單,不要慌.app

標準庫的函數基本都是內聯函數 inline修飾.不知道啥是內聯函數的,翻翻我前面的文章吧.less

1.run函數

@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())}
    
   
複製代碼

2.let函數

@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表示;
複製代碼

3.with函數

@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
  
  
複製代碼

4.also函數

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函數.
     
複製代碼

5.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

6.takeIf,takeUnless

@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;  
      
     
        
複製代碼

7.repeat函數

@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給我解放的生產力.

相關文章
相關標籤/搜索