上一篇 - 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 學習筆記(十四)淺讀協程