
序言
最近一直在學(xué)習(xí) kotlin ,他給我的感覺是一門非常使用、簡潔的語言。Kotlin 支持函數(shù)式編程,而 Lambda 在 Kotlin 和 Kotlin DSL 中扮演著很重要的角色,是實(shí)現(xiàn)整潔代碼的必備語法糖。
Lambda 表達(dá)式的語法
一個(gè) lambda 把一小段行為進(jìn)行編碼,你能把它當(dāng)作值到處傳遞。它可以被獨(dú)立地聲明并存儲(chǔ)到一個(gè)變量中,但是更常見的還是直接聲明它井傳遞給函數(shù)(高階函數(shù))。

Kotlin lambda 表達(dá)式始終用花括號(hào)包圍。注意實(shí)參并沒有用括號(hào)括起來
頭把實(shí)參列表和 lambda 的函數(shù)體隔開。
高階函數(shù)
就是這個(gè)函數(shù)可以接受另一個(gè)函數(shù)作為參數(shù)或者返回值
函數(shù)的形參總是 首先是括號(hào)里面是函數(shù)的入?yún)㈩愋?,然后箭頭后面跟的是函數(shù)返回值類型,沒有返回值要指定 Unit 如圖:

下面是一個(gè) Android 中最常見的 view 的點(diǎn)擊事件在 分別用 java 和 kotlin 來實(shí)現(xiàn)
java 寫法
// java 1、首先要聲明接口 2、實(shí)例這個(gè)接口創(chuàng)建一個(gè)匿名內(nèi)部類
public interface OnClickListener {
void onClick(View v);
}
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View view) {
/*點(diǎn)擊后執(zhí)行的動(dòng)作*/
}
)
kotlin lambda 寫法
// kotlin 高級(jí)函數(shù)聲明( 傳入 lambda ) view 類型參數(shù) 沒有返回值
fun setOnClickListener(listener: (View) -> Unit)
// kotlin 十分簡潔
button.setOnClickListener({ v: View -> print(v.name)})
kotlin lambda 如果這個(gè)函數(shù)的最后一個(gè)參數(shù)是一個(gè)函數(shù),我們可以把這個(gè)函數(shù)移動(dòng)到圓括號(hào)外面
button.setOnClickListener() { v: View -> print(v.name)}
kotlin lambda 如果這個(gè)函數(shù)只有一個(gè)參數(shù),我們可以省略這個(gè)圓括號(hào)
button.setOnClickListener{ v: View -> print(v.name)}
// 用 it 代替參數(shù)
button.setOnClickListener{ print(it.name)}
// 如果沒有用到 v 這個(gè)參數(shù)可以進(jìn)一步簡化
button.setOnClickListener { print("我就是簡潔...")}
我們將會(huì)在下一章中講解 lambda 表達(dá)式的經(jīng)典用途和集合一起工作,kotlin 是如何提供那么方便的集合庫
帶接收者的 lambda 和擴(kuò)展函數(shù)類型
首先我們還是先通過 來看為啥要用這個(gè)帶接收者的 lambda,他是怎么做到優(yōu)化的。
1、先定義一個(gè)個(gè)以普通 lambda 作為參數(shù)的 buildString 函數(shù)。
/**
* @param builderAction 定義函數(shù)類型的參數(shù)
*/
fun buildStringNormalLm(builderAction: (StringBuilder) -> Unit): String {
val sb = java.lang.StringBuilder()
// 傳遞一個(gè) StringBuilder 對(duì)象作為 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 這個(gè)對(duì)象執(zhí)行多次操作,我們不想反復(fù)把對(duì)象的名稱寫出來 就是未來這個(gè)目的....
3、要做到這點(diǎn),需要將 lambda 轉(zhuǎn)換成帶接收者的 lambda。
/**
* @param builderAction 定義帶接收者的函數(shù)類型的參數(shù)
* StringBuilder. () -> Unit 擴(kuò)展函數(shù)聲明
*/
fun buildStringReceiverLm(builderAction: StringBuilder. () -> Unit): String {
val sb = java.lang.StringBuilder()
// 傳遞一個(gè) String Builder 實(shí)例作為 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í)例那 ?
- 主要是我們用 擴(kuò)展函數(shù)類型 取代 普通函數(shù)類型 來聲明參數(shù)的類型 。擴(kuò)展函數(shù)類型的聲明如下圖:Kotlin in Action
為什么要用擴(kuò)展函數(shù)類型?不需要顯式的修飾符就可以訪問一個(gè)外部類型的成
員讓我們想起了擴(kuò)展函數(shù),它可以讓我們?yōu)樵诖a其他地方定義的類定義自己的方法。擴(kuò)展函數(shù)和帶接收者的 lambda 都有一個(gè)接收者對(duì)象 ,當(dāng)函數(shù)被調(diào)用的時(shí)候需要提供這個(gè)對(duì)象,它在函數(shù)體內(nèi)是可用的。實(shí)際上一個(gè)個(gè)擴(kuò)展函數(shù)類型描述了可以被當(dāng)作擴(kuò)展函數(shù)來調(diào)用的代碼塊。
仔細(xì)看下面的截圖以及備注我想你一定能看明白

下一節(jié)我們會(huì)通過展示 Kotlin 標(biāo)準(zhǔn)庫中的 with 函數(shù)和 apply 函數(shù),來進(jìn)一步說明 帶接收者的 lambda 實(shí)際項(xiàng)目中用到的地方。
參考資料
Kotlin之美——DSL篇
《Kotlin 實(shí)戰(zhàn)》
