序言
最近一直在學習 kotlin 饼疙,他給我的感覺是一門非常使用俭茧、簡潔的語言挺物。Kotlin 支持函數(shù)式編程豪椿,而 Lambda 在 Kotlin 和 Kotlin DSL 中扮演著很重要的角色,是實現(xiàn)整潔代碼的必備語法糖叨恨。
Lambda 表達式的語法
一個 lambda 把一小段行為進行編碼柳刮,你能把它當作值到處傳遞。它可以被獨立地聲明并存儲到一個變量中痒钝,但是更常見的還是直接聲明它井傳遞給函數(shù)(高階函數(shù))秉颗。
Kotlin lambda 表達式始終用花括號包圍。注意實參并沒有用括號括起來
頭把實參列表和 lambda 的函數(shù)體隔開送矩。
高階函數(shù)
就是這個函數(shù)可以接受另一個函數(shù)作為參數(shù)或者返回值
函數(shù)的形參總是 首先是括號里面是函數(shù)的入?yún)㈩愋筒仙缓蠹^后面跟的是函數(shù)返回值類型,沒有返回值要指定 Unit 如圖:
下面是一個 Android 中最常見的 view 的點擊事件在 分別用 java 和 kotlin 來實現(xiàn)
java 寫法
// java 1栋荸、首先要聲明接口 2菇怀、實例這個接口創(chuàng)建一個匿名內(nèi)部類
public interface OnClickListener {
void onClick(View v);
}
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View view) {
/*點擊后執(zhí)行的動作*/
}
)
kotlin lambda 寫法
// kotlin 高級函數(shù)聲明( 傳入 lambda ) view 類型參數(shù) 沒有返回值
fun setOnClickListener(listener: (View) -> Unit)
// kotlin 十分簡潔
button.setOnClickListener({ v: View -> print(v.name)})
kotlin lambda 如果這個函數(shù)的最后一個參數(shù)是一個函數(shù),我們可以把這個函數(shù)移動到圓括號外面
button.setOnClickListener() { v: View -> print(v.name)}
kotlin lambda 如果這個函數(shù)只有一個參數(shù)晌块,我們可以省略這個圓括號
button.setOnClickListener{ v: View -> print(v.name)}
// 用 it 代替參數(shù)
button.setOnClickListener{ print(it.name)}
// 如果沒有用到 v 這個參數(shù)可以進一步簡化
button.setOnClickListener { print("我就是簡潔...")}
我們將會在下一章中講解 lambda 表達式的經(jīng)典用途和集合一起工作爱沟,kotlin 是如何提供那么方便的集合庫
帶接收者的 lambda 和擴展函數(shù)類型
首先我們還是先通過 來看為啥要用這個帶接收者的 lambda,他是怎么做到優(yōu)化的匆背。
1呼伸、先定義一個個以普通 lambda 作為參數(shù)的 buildString 函數(shù)。
/**
* @param builderAction 定義函數(shù)類型的參數(shù)
*/
fun buildStringNormalLm(builderAction: (StringBuilder) -> Unit): String {
val sb = java.lang.StringBuilder()
// 傳遞一個 StringBuilder 對象作為 lambda 的參數(shù)
builderAction(sb)
return sb.toString()
}
// 調(diào)用普通的 lambda
val s = buildStringNormalLm {
it.append("Hello,")
it.append("World")
}
print(s)
// 打印結(jié)果 Hello,World
2钝尸、首先 it 這個對象執(zhí)行多次操作括享,我們不想反復把對象的名稱寫出來 就是未來這個目的....
3搂根、要做到這點,需要將 lambda 轉(zhuǎn)換成帶接收者的 lambda铃辖。
/**
* @param builderAction 定義帶接收者的函數(shù)類型的參數(shù)
* StringBuilder. () -> Unit 擴展函數(shù)聲明
*/
fun buildStringReceiverLm(builderAction: StringBuilder. () -> Unit): String {
val sb = java.lang.StringBuilder()
// 傳遞一個 String Builder 實例作為 lambda 接收者
sb.builderAction()
return sb.toString()
}
// 調(diào)用帶接收者的 lambda
val s = buildStringReceiverLm {
append("Hello,")
append("World")
}
print(s)
// 打印結(jié)果 Hello,World
那為什么在 buildStringReceiverLm() 中可以直接調(diào)用 StringBuilder 實例那 剩愧?
- 主要是我們用 擴展函數(shù)類型 取代 普通函數(shù)類型 來聲明參數(shù)的類型 。擴展函數(shù)類型的聲明如下圖:
為什么要用擴展函數(shù)類型澳叉?不需要顯式的修飾符就可以訪問一個外部類型的成
員讓我們想起了擴展函數(shù)隙咸,它可以讓我們?yōu)樵诖a其他地方定義的類定義自己的方法沐悦。擴展函數(shù)和帶接收者的 lambda 都有一個接收者對象 成洗,當函數(shù)被調(diào)用的時候需要提供這個對象,它在函數(shù)體內(nèi)是可用的藏否。實際上一個個擴展函數(shù)類型描述了可以被當作擴展函數(shù)來調(diào)用的代碼塊瓶殃。
仔細看下面的截圖以及備注我想你一定能看明白
下一節(jié)我們會通過展示 Kotlin 標準庫中的 with 函數(shù)和 apply 函數(shù),來進一步說明 帶接收者的 lambda 實際項目中用到的地方副签。
參考資料
Kotlin之美——DSL篇
《Kotlin 實戰(zhàn)》