【Kotlin】六、Lambdas表達(dá)式

介紹

Lambda表達(dá)式是一種很簡單的方法,去定義一個(gè)匿名函數(shù)。Lambda是非常有用
的,因?yàn)樗鼈儽苊馕覀內(nèi)懸恍┌四承┖瘮?shù)的抽象類或者接口,然后在類中去
實(shí)現(xiàn)它們。在Kotlin,我們把一個(gè)函數(shù)作為另一個(gè)函數(shù)的參數(shù)。

簡化setOnClickListener()

我們用Android中非常典型的例子去解釋它是怎么工作
的: View.setOnClickListener() 方法。如果我們想用Java的方式去增加點(diǎn)擊
事件的回調(diào),我首先要編寫一個(gè) OnClickListener 接口:

public interface OnClickListener {
    void onClick(View v);
}

然后我們要編寫一個(gè)匿名內(nèi)部類去實(shí)現(xiàn)這個(gè)接口:

view.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        Toast.makeText(v.getContext(), "Click", Toast.LENGTH_SHORT).show();
    }
})

我們將把上面的代碼轉(zhuǎn)換成Kotlin(使用了Anko的toast函數(shù)):

view.setOnClickListener(object : OnClickListener {
    override fun onClick(v: View) {
        toast("Click")
    }
}

很幸運(yùn)的是,Kotlin允許Java庫的一些優(yōu)化,Interface中包含單個(gè)函數(shù)可以被替代
為一個(gè)函數(shù)。如果我們這么去定義了,它會(huì)正常執(zhí)行:

fun setOnClickListener(listener: (View) -> Unit)

一個(gè)lambda表達(dá)式通過參數(shù)的形式被定義在箭頭的左邊(被圓括號(hào)包圍),然后在
箭頭的右邊返回結(jié)果值。在這個(gè)例子中,我們接收一個(gè)View,然后返回一個(gè)
Unit(沒有東西)。所以根據(jù)這種思想,我們可以把前面的代碼簡化成這樣:

view.setOnClickListener({ view -> toast("Click")})

這是非常棒的簡化!當(dāng)我們定義了一個(gè)方法,我們必須使用大括號(hào)包圍,然后在箭
頭的左邊指定參數(shù),在箭頭的右邊返回函數(shù)執(zhí)行的結(jié)果。如果左邊的參數(shù)沒有使用
到,我們甚至可以省略左邊的參數(shù):

view.setOnClickListener({ toast("Click") })

如果這個(gè)函數(shù)的最后一個(gè)參數(shù)是一個(gè)函數(shù),我們可以把這個(gè)函數(shù)移動(dòng)到圓括號(hào)外
面:

view.setOnClickListener() { toast("Click") }

并且,最后,如果這個(gè)函數(shù)只有一個(gè)參數(shù),我們可以省略這個(gè)圓括號(hào):

view.setOnClickListener { toast("Click") }

比原始的Java代碼簡短了5倍多,并且更加容易理解它所做的事情。非常讓人影響
深刻。

擴(kuò)展語言

多虧這些改變,我們可以去創(chuàng)建自己的 builder 和代碼塊。我們已經(jīng)在使用一些
有趣的函數(shù),比如 with 。如下簡單的實(shí)現(xiàn):

inline fun <T> with(t: T, body: T.() -> Unit) { t.body() }

這個(gè)函數(shù)接收一個(gè) T 類型的對(duì)象和一個(gè)被作為擴(kuò)展函數(shù)的函數(shù)。它的實(shí)現(xiàn)僅僅是
讓這個(gè)對(duì)象去執(zhí)行這個(gè)函數(shù)。因?yàn)榈诙€(gè)參數(shù)是一個(gè)函數(shù),所以我們可以把它放在
圓括號(hào)外面,所以我們可以創(chuàng)建一個(gè)代碼塊,在這這個(gè)代碼塊中我們可以使
用 this 和直接訪問所有的public的方法和屬性:

with(forecast) {
    Picasso.with(itemView.ctx).load(iconUrl).into(iconView)
    dateView.text = date
    descriptionView.text = description
    maxTemperatureView.text = "$high"
    minTemperatureView.text = "$low"
    itemView.setOnClickListener { itemClick(this) }
}

內(nèi)聯(lián)函數(shù)

內(nèi)聯(lián)函數(shù)與普通的函數(shù)有點(diǎn)不同。一個(gè)內(nèi)聯(lián)函數(shù)會(huì)在編譯的時(shí)候被替換
掉,而不是真正的方法調(diào)用。這在一些情況下可以減少內(nèi)存分配和運(yùn)行時(shí)
開銷。舉個(gè)例子,如果我們有一個(gè)函數(shù),只接收一個(gè)函數(shù)作為它的參數(shù)。
如果是一個(gè)普通的函數(shù),內(nèi)部會(huì)創(chuàng)建一個(gè)含有那個(gè)函數(shù)的對(duì)象。另一方
面,內(nèi)聯(lián)函數(shù)會(huì)把我們調(diào)用這個(gè)函數(shù)的地方替換掉,所以它不需要為此生
成一個(gè)內(nèi)部的對(duì)象。

另一個(gè)例子:我們可以創(chuàng)建代碼塊只提供 Lollipop 或者更高版本來執(zhí)行:

inline fun supportsLollipop(code: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        code()
    }
}

它只是檢查版本,然后如果滿足條件則去執(zhí)行?,F(xiàn)在我們可以這么做:

supportsLollipop {
    window.setStatusBarColor(Color.BLACK)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考YYModel 學(xué)習(xí)筆記(一) 一.NSObject+YYModel.h NS_ASSUME_NONNULL_...
    陌尚煙雨遙閱讀 498評(píng)論 0 0
  • 2017年4月19日~2017年7月21日/ 趟著這趟水到了年末。 主要是感覺不怎么像以前那么冷清了 果然是時(shí)間的...
    你沒在我的夢里閱讀 234評(píng)論 0 0
  • 這幾天竟然追了悟空傳的電影版和小說版,比較一下就知道小說的精彩之處在于用現(xiàn)在無厘頭的敘說方式描述了師徒四人的搞笑故...
    笑傲江湖201710閱讀 249評(píng)論 0 0
  • 想你了,你想我了嗎,母親。看見月亮了嗎?它是我的信使。當(dāng)它還是船的時(shí)候,我就派它去了。我一點(diǎn)一點(diǎn)的填滿它的肚子,都...
    虞亦閱讀 334評(píng)論 2 1
  • 伴隨著自己的哭聲來到這個(gè)世間,又在他人的哭聲中離開,這中間的過程,就是一個(gè)人的一生。 這一生,由無數(shù)個(gè)經(jīng)歷組成;這...
    瑾初閱讀 604評(píng)論 0 1

友情鏈接更多精彩內(nèi)容