天天看點

Kotlin 學習筆記(十三)高階函數

Kotlin 學習筆記(十三)高階函數

上一篇 - kotlin中 集合序列使用、操作符彙總

前言

本篇部落格為本人學習Kotlin 中所遇到的問題,如果哪裡寫的不對,希望歐大佬幫忙指出,多謝。

高階函數簡單介紹

  一句話概括高階函數:在Kotlin中,高階函數即指:将函數用作一個函數的參數或者傳回值的函數。

參數為高階函數

  先看一段String.kt 檔案中的擴充函數

/**
 * Returns the sum of all values produced by [selector] function applied to each character in the char sequence.
 */
// inline 前邊寫過是内聯函數 (一般都和 lambda結合使用 ,優化函數調用詳情參考 學習筆記十)
// CharSequence. 則是擴充函數
public inline fun CharSequence.sumByDouble(selector: (Char) -> Double): Double {
    // selector參數 也是一個fun ,傳入char對象 輸入 Double對象
    var sum: Double = 0.0
    for (element in this) {
        sum += selector(element)
    }
    return sum
}
           

  經過注釋講解,大概猜到該函數是将傳入的字元串 周遊轉換為 Double,并增加,最後傳回Double 類型的總和。

傳回值為高階函數

這裡使用官網上的一個例子

// 參數一接收 Lock類型 、接受一個無參且傳回類型為T的函數作為參數二
fun <T> lock(lock: Lock, body:()->T):T{
        lock.lock()
        try {
            // 函數傳回值
            return body()
        }
        finally {
            lock.unlock()
        }
    }
           

我們通過一個僞代碼,更直接的看一下

fun toBeSynchronized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchronized)    

//簡寫
val result = lock(lock, {sharedResource.operation()} )
           

常用高階函數

都集中在 Standard.kt

TODO

源碼 :

/**
 * Always throws [NotImplementedError] stating that operation is not implemented.
 *
 * @param reason a string explaining why the implementation is missing.
 */
@kotlin.internal.InlineOnly
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")
// inline 添加上有利于調用的時候 不需要再跳轉到改函數中使用,減少運作消耗時間
           

run函數

@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
    //契約 (run also with apply also 标準函數庫都用到了契約)
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}
           

  該契約表示告訴編譯器:調用run函數後産生效果是指定block lamba表達式參數在适當的位置被調用。适當位置就是block lambda表達式隻能在自己函數(這裡就是指外層apply函數)被調用期間被調用,當run函數被調用結束後,block表達式不能被執行,并且指定了InvocationKind.EXACTLY_ONCE表示block lambda表達式隻能被調用一次,此外這個外層函數還必須是個inline内聯函數。(契約更像告訴編譯器自身上下文關系)

  當我們需要執行一個代碼塊的時候就可以用到這個函數,并且這個代碼塊是獨立的。即我可以在run()函數中寫一些和項目無關的代碼,因為它不會影響項目的正常運作。

舉例:

private fun printString(index: Int) {
        val str = "kotlin"
        var l = kotlin.run {
            when (index) {
                1 -> {
                    "java"
                }
                2 -> {
                    "php"
                }
                else -> {
                    "lua"
                }
            }
        }.length
        print(str + l)
    }
           

如上述代碼,在print代碼執行的時候,會等待 run方法塊的執行結果傳回。

T.run()

大眼看過去 感覺 T.run() 和 run() 差别不大,但是在使用的時候會有不小的差別

源碼:

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}
           

我們通過一段代碼模拟一下使用環境

private var str = "java"

    fun printStr(){
        str.run {
            print("${this.length}")
            print("${this.last()}")
            print("${first()}")
        }
    }
           

上述代碼中 T.run方法塊中可以使用this關鍵字 來代替本身,也可以省略,更适合多行代碼使用同一對象的情況,如果通過源碼檢視,可以發現 block()就是個T類型的擴充函數。

關于更多的高階函數 also with apply 等請移步 Kotlin中的庫函數: run、with、let、also和apply

下一篇 - Kotlin 學習筆記(十四)淺讀協程