Kotlin函數(shù)式編程 (2)??Lambda表達(dá)式

  • Lambda 表達(dá)式標(biāo)準(zhǔn)語(yǔ)法格式
  • 使用Lambda 表達(dá)式
  • Lambda 表達(dá)式簡(jiǎn)化寫(xiě)法
    • ??參數(shù)類(lèi)型推導(dǎo)簡(jiǎn)化
    • ??使用尾隨 Lambda 表達(dá)式
    • ??省略參數(shù)聲明
  • Lambda 表達(dá)式與 return 語(yǔ)句

??Lambda 表達(dá)式是一種匿名函數(shù),可以作為表達(dá)式函數(shù)參數(shù)函數(shù)返回值 使用键耕。

一、Lambda 表達(dá)式標(biāo)準(zhǔn)語(yǔ)法格式

??Lambda 表達(dá)式的語(yǔ)法很靈活勺美,下面只是它的標(biāo)準(zhǔn)語(yǔ)法格式:

{ 參數(shù)列表 ->
    Lambda 體
}

??Lambda 表達(dá)式的參數(shù)列表與函數(shù)的參數(shù)列表形式類(lèi)似,但是 Lambda 表達(dá)式參數(shù)列表前后 沒(méi)有小括號(hào)() 。箭頭符號(hào)將參數(shù)列表和 Lambda 體分隔開(kāi)养盗,Lambda 表達(dá)式不需要聲明返回類(lèi)型昂利。Lambda 表達(dá)式可以有返回值届腐,如果 沒(méi)有 return 語(yǔ)句,Lambda 體的最后一個(gè)表達(dá)式就是 Lambda 表達(dá)式的返回值蜂奸;如果 有 return 語(yǔ)句犁苏,返回值是 return 語(yǔ)句后面的表達(dá)式。

fun calculate(opr: Char): (Int, Int) -> Int = when (opr) {
    '+' -> { a: Int, b: Int -> a + b } // Lambda表達(dá)式
    '-' -> { a: Int, b: Int -> a - b } // Lambda表達(dá)式
    '*' -> { a: Int, b: Int -> a * b } // Lambda表達(dá)式
    else -> { a: Int, b: Int -> a / b } // Lambda表達(dá)式
}

fun main(args: Array<String>) {
    val f1 = calculate('+')
    println(f1(10, 5))  // 15
    
    val f2 = calculate('-')
    println(f2(10, 5))  // 5
    
    val f3 = calculate('*')
    println(f3(10, 5))  // 50
    
    val f4 = calculate('/')
    println(f4(10, 5))  // 2
}

??上面代碼fun calculate(opr: Char)后面的(Int, Int) -> Int返回值類(lèi)型(函數(shù)類(lèi)型)扩所,而不是 Lambda 表達(dá)式围详。

??提示:Lambda 表達(dá)式與函數(shù)、匿名函數(shù)一樣都有函數(shù)類(lèi)型祖屏,但從 Lambda 表達(dá)式的定義中只能看到參數(shù)類(lèi)型短曾,看不到返回類(lèi)型聲明,那是因?yàn)榉祷仡?lèi)型可以通過(guò)上下文推導(dǎo)出來(lái)赐劣。

二嫉拐、使用Lambda 表達(dá)式

??Lambda 表達(dá)式也是函數(shù)類(lèi)型,可以聲明變量魁兼,也可以作為其他函數(shù)的參數(shù)或者返回值使用婉徘。

fun calculatePrint(a: Int, b: Int, opr: Char, func: (Int, Int) -> Int) {
    println("$a $opr $b = ${func(a, b)}")
}

fun main(args: Array<String>) {
    calculatePrint(10, 5, '+', { a, b -> a + b }) // Lambda作為參數(shù)
    calculatePrint(10, 5, '-', func = { a, b -> a - b }) // Lambda作為參數(shù)(命名參數(shù)方式傳參)
}

三、Lambda 表達(dá)式簡(jiǎn)化寫(xiě)法

??kotlin 提供了多種 Lambda 表達(dá)式的簡(jiǎn)化寫(xiě)法咐汞。

1盖呼、??參數(shù)類(lèi)型推導(dǎo)簡(jiǎn)化

??kotlin 編譯期可以根據(jù)上下文環(huán)境推導(dǎo)出參數(shù)類(lèi)型和返回值類(lèi)型。例如上面代碼定義的高階函數(shù) calculate(opr: Char) 返回值類(lèi)型為 (Int, Int) -> Int化撕,下面給出此高階函數(shù)的 Lambda 表達(dá)式的標(biāo)準(zhǔn)版 和 簡(jiǎn)化版:

// 標(biāo)準(zhǔn)類(lèi)型的Lambda表達(dá)式
{ a: Int, b: Int -> a + b}

??kotlin 可以根據(jù)高階函數(shù)calculate的返回值類(lèi)型(Int, Int) -> Int几晤,推斷出 Lambda 表達(dá)式參數(shù)為 Int 類(lèi)型,返回值類(lèi)型也為 Int 類(lèi)型植阴。

// 簡(jiǎn)化版
{ a, b -> a + b}

??完整的簡(jiǎn)化版 calculate 代碼:

fun calculate(opr: Char): (Int, Int) -> Int = when (opr) {
    '+' -> { a, b -> a + b }
    '-' -> { a, b -> a - b }
    '*' -> { a, b -> a * b }
    else -> { a, b -> a / b }
}

2蟹瘾、??使用尾隨 Lambda 表達(dá)式

??如果一個(gè)函數(shù)的最后一個(gè)參數(shù)是 Lambda 表達(dá)式,那么這個(gè) Lambda 表達(dá)式可以放到函數(shù)括號(hào)之后掠手。

fun calculatePrint(a: Int, b: Int, opr: Char, func: (Int, Int) -> Int) {
    println("$a $opr $b = ${func(a, b)}")
}

fun calculatePrint105(func: (Int, Int) -> Int) {
    println("${func(10, 5)}")
}

fun main(args: Array<String>) {
    // 標(biāo)準(zhǔn)調(diào)用
    calculatePrint(10, 5, '+', { a, b -> a + b })
    calculatePrint105({ a, b -> a + b })

    // 尾隨Lambda表達(dá)式
    calculatePrint(10, 5, '+') { a, b -> a + b } // 1??
    calculatePrint105() { a, b -> a + b } // 2??

    // calculatePrint105(){a, b -> a + b} 再簡(jiǎn)化版本
    calculatePrint105 { a, b -> a + b }  // 尾隨Lambda表達(dá)式憾朴,如果沒(méi)有參數(shù)可以省略括號(hào)
}

??注意:尾隨 Lambda 表達(dá)式容易被誤認(rèn)為是函數(shù)聲明,如上述代碼第1??喷鸽、2??行众雷,是不是會(huì)認(rèn)為是一個(gè)函數(shù)?但它缺少函數(shù)聲明的必要關(guān)鍵字 fun,同時(shí)也缺少參數(shù)類(lèi)型砾省,命名規(guī)定等鸡岗。

3、??省略參數(shù)聲明

??如果 Lambda 表達(dá)式的參數(shù)只有一個(gè)编兄,并且能夠根據(jù)上下文環(huán)境推導(dǎo)出它的數(shù)據(jù)類(lèi)型纤房,那么這個(gè)參數(shù)聲明可以省略,在 Lambda 體中使用隱式參數(shù) it 替代 Lambda 表達(dá)式的參數(shù)翻诉。

fun reversePrint(word: String, func: (String) -> String) {
    println("${func(word)}")
}

fun main(args: Array<String>) {
    // 未省略參數(shù)說(shuō)明
    reversePrint("hello") { word -> word.reversed() }
    // 省略參數(shù)說(shuō)明
    reversePrint("hello") { it.reversed() }
    
    val result1: (String) -> Unit = { print(it) } // 3??省略參數(shù)說(shuō)明,并且可以根據(jù)result1聲明的函數(shù)類(lèi)型捌刮,判斷出隱式參數(shù)it的類(lèi)型
    val result2 = { a: String -> print(a) } // 4??不能省略參數(shù)說(shuō)明碰煌,無(wú)法根據(jù)上下環(huán)境判斷出參數(shù)類(lèi)型
}

??注意:Lambda體中 it 隱式變量是由 kotlin 編譯器生成的,它的使用有兩個(gè)前提:一是 Lambda 表達(dá)式只有一個(gè)參數(shù)绅作,二是根據(jù)上下文環(huán)境能夠推導(dǎo)出參數(shù)類(lèi)型芦圾。比較代碼第3??、4??行會(huì)發(fā)現(xiàn)俄认,代碼第4??行由于 result2 沒(méi)有指定數(shù)據(jù)類(lèi)型个少,編輯器不能推導(dǎo)出 Lambda 表達(dá)式的參數(shù)類(lèi)型,所以不能使用 it眯杏。而代碼第3??行夜焦,由于 result1 指定了數(shù)據(jù)類(lèi)型為 (String) -> Unit,編輯器能夠推導(dǎo)出 Lambda 表達(dá)式的參數(shù)類(lèi)型岂贩,所以可以使用 it茫经。

四、Lambda 表達(dá)式與 return 語(yǔ)句

??Lambda 表達(dá)式可以使用 return 語(yǔ)句萎津,它會(huì)使程序跳出 Lambda 表達(dá)式體卸伞;
??例如:函數(shù) sum 內(nèi)部有一個(gè) Lambda 表達(dá)式,在 Lambda 表達(dá)式內(nèi)執(zhí)行 return 語(yǔ)句锉屈,則會(huì)直接結(jié)束 sum 函數(shù)荤傲,而 return語(yǔ)句的返回值,作為了 sum 函數(shù)的返回值颈渊。

fun sum(vararg num: Int): Int {
    var total = 0
    num.forEach {
        if (it == 10) return -1
        total += it
    }
    return total
}

fun main(args: Array<String>) {
    val n = sum(1, 2, 10, 3)
    println(n)
}

2019-06-05 12:48:22.000 17599-17599/cn.ak.kot I/System.out: -1

??那么像上面的代碼能通過(guò) return 結(jié)束 Lambda 表達(dá)式嗎遂黍?當(dāng)然是可以的,但需要在 return 時(shí)指定返回標(biāo)簽俊嗽,返回標(biāo)簽用法在Kotlin基礎(chǔ)認(rèn)識(shí) (8)程序流程控制中有介紹妓湘。修改后的代碼如下:

fun sum(vararg num: Int): Int {
    var total = 0
    num.forEach {
        if (it == 10) return@forEach // 5??@forEach是隱式聲明標(biāo)簽
        total += it
    }
    return total
}

fun main(args: Array<String>) {
    val n = sum(1, 2, 10, 3)
    println(n)
}

2019-06-05 14:18:09.269 22302-22302/cn.ak.kot I/System.out: 6

??上述代碼第5??行是使用隱式標(biāo)簽 @forEach 結(jié)束本次 Lambda 表達(dá)式運(yùn)行。

??提示:forEach 是集合乌询、數(shù)組或區(qū)間的函數(shù)榜贴,它后面是一個(gè) Lambda 表達(dá)式,集合、數(shù)組或區(qū)間對(duì)象調(diào)用 forEach 函數(shù)時(shí)唬党,會(huì)將它們的每一個(gè)元素傳遞給 Lambda 表達(dá)式并執(zhí)行鹃共。

??下面是一個(gè)顯示使用標(biāo)簽的案例:

fun main(args: Array<String>) {
    val add = label@ {    // 打一個(gè)標(biāo)簽,標(biāo)記結(jié)束位置
        val a = 1
        val b = 2
        return@label 10 // 結(jié)束運(yùn)行驶拱,返回到標(biāo)簽位置
        a + b   // 這句代碼實(shí)際是永遠(yuǎn)執(zhí)行不到的
    }
    println(add())
}

2019-06-05 14:25:10.968 23002-23002/cn.ak.kot I/System.out: 10
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末霜浴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蓝纲,更是在濱河造成了極大的恐慌阴孟,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件税迷,死亡現(xiàn)場(chǎng)離奇詭異永丝,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)箭养,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)慕嚷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人毕泌,你說(shuō)我怎么就攤上這事喝检。” “怎么了撼泛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵挠说,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我愿题,道長(zhǎng)纺涤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任抠忘,我火速辦了婚禮撩炊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘崎脉。我一直安慰自己拧咳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布囚灼。 她就那樣靜靜地躺著骆膝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪灶体。 梳的紋絲不亂的頭發(fā)上阅签,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音蝎抽,去河邊找鬼政钟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的养交。 我是一名探鬼主播精算,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼碎连!你這毒婦竟也來(lái)了灰羽?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鱼辙,失蹤者是張志新(化名)和其女友劉穎廉嚼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體倒戏,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怠噪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了峭梳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹂喻,死狀恐怖葱椭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情口四,我是刑警寧澤孵运,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蔓彩,受9級(jí)特大地震影響治笨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赤嚼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一旷赖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧更卒,春花似錦等孵、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至上枕,卻和暖如春咐熙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辨萍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工棋恼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓蘸泻,卻偏偏與公主長(zhǎng)得像琉苇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悦施,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345