Kotlin高階函數(shù)與Lambda表達式

Kotlin 函數(shù)都是頭等的许赃,這意味著它們可以存儲在變量與數(shù)據(jù)結(jié)構(gòu)中、作為參數(shù)傳遞給其他高階函數(shù)以及從其 他高階函數(shù)返回洽胶。可以像操作任何其他非函數(shù)值?樣操作函數(shù)裆馒。

一姊氓、高階函數(shù)

高階函數(shù)是將函數(shù)用作參數(shù)或返回值的函數(shù)。

二喷好、函數(shù)類型

Kotlin 使用類似 (Int) -> String 的?系列函數(shù)類型來處理函數(shù)的聲明:val onClick: () -> Unit = ……翔横。
這些類型具有與函數(shù)簽名相對應(yīng)的特殊表示法,即它們的參數(shù)和返回值:

  • 所有函數(shù)類型都有?個圓括號括起來的參數(shù)類型列表以及?個返回類型:(A, B) -> C 表?接受類型分 別為 A 與 B 兩個參數(shù)并返回?個 C 類型值的函數(shù)類型梗搅。參數(shù)類型列表可以為空禾唁,如 () -> A 。Unit 返 回類型不可省略无切。
  • 函數(shù)類型可以有?個額外的接收者類型荡短,它在表示法中的點之前指定:類型 A.(B) -> C 表示可以在 A 的接收者對象上以?個B類型參數(shù)來調(diào)用并返回?個 C 類型值的函數(shù)。帶有接收者的函數(shù)字面值通常與這些類型?起使用哆键。
  • 掛起函數(shù)屬于特殊種類的函數(shù)類型掘托,它的表示法中有?個 suspend 修飾符 ,例如 suspend () -> Unit 或者 suspend A.(B) -> C 籍嘹。

函數(shù)類型表示法可以選擇性地包含函數(shù)的參數(shù)名:(x: Int, y: Int) -> Point 闪盔。這些名稱可用于表明參數(shù)的含義弯院。

  • 如需將函數(shù)類型指定為可空,請使?圓括號:((Int, Int) -> Int)?泪掀。
  • 函數(shù)類型可以使?圓括號進?接合:(Int) -> ((Int) -> Unit)
  • 箭頭表是法是右結(jié)合的听绳,(Int) -> (Int) -> Unit 與前述?例等價,但不等于 ((Int) -> (Int)) -> Unit异赫。

還可以通過使?類型別名給函數(shù)類型起?個別稱:

typealias ClickHandler = (Button, ClickEvent) -> Unit

1.函數(shù)類型實例化

  • 使用函數(shù)字面值的代碼塊椅挣,采用以下形式之?:
    1. lambda 表達式: { a, b -> a + b }
    2. 匿名函數(shù): fun(s: String): Int { return s.toIntOrNull() ?: 0 }
  • 使用已有聲明的可調(diào)用引用:
    1. 頂層、局部塔拳、成員贴妻、擴展函數(shù):::isOdd 、String::toInt
    2. 頂層蝙斜、成員名惩、擴展屬性:List<Int>::size
    3. 構(gòu)造函數(shù):::Regex
  • 使?實現(xiàn)函數(shù)類型接?的?定義類的實例:
class IntTransformer : (Int) -> Int {
    override operator fun invoke(x: Int): Int = TODO()
}

val intFunction: (Int) -> Int = IntTransformer()

帶與不帶接收者的函數(shù)類型非字面值可以互換,其中接收者可以替代第?個參數(shù)孕荠,反之亦然娩鹉。例如,(A, B) -> C 類型的值可以傳給或賦值給期待 A.(B) -> C 的地方稚伍,反之亦然

val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun
fun runTransformation(f: (String, Int) -> String): String {
    return f("hello", 3)
}

val result = runTransformation(repeatFun)

2.函數(shù)類型實例調(diào)用

函數(shù)類型的值可以通過其 invoke(……) 操作符調(diào)用:f.invoke(x) 或者直接 f(x) 弯予。
如果該值具有接收者類型,那么應(yīng)該將接收者對象作為第?個參數(shù)傳遞个曙。調(diào)用帶有接收者的函數(shù)類型值的另?個方式是在其前面加上接收者對象锈嫩,就好比該值是?個擴展函數(shù):1.foo(2)

val stringPlus: (String, String) -> String = String::plus
val intPlus: Int.(Int) -> Int = Int::plus
println (stringPlus.invoke("<-", "->"))
println (stringPlus("Hello, ","world!"))
println (intPlus.invoke(1, 1))
println (intPlus(1, 2))
println (2.intPlus(3)) // 類擴展調(diào)?

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

用內(nèi)聯(lián)函數(shù)可以為高階函數(shù)提供靈活的控制流。

三垦搬、Lambda表達式和匿名函數(shù)

lambda 表達式與匿名函數(shù)是“函數(shù)字面值”呼寸,即未聲明的函數(shù)

1.Lambda 表達式語法

lambda 表達式總是括在花括號中,完整語法形式的參數(shù)聲明放在花括號內(nèi)猴贰,并有可選的類型標(biāo)注对雪,函數(shù)體跟在 ?個 -> 符號之后。如果推斷出的該 lambda 的返回類型不是 Unit米绕,那么該 lambda 主體中的最后?個(或 可能是單個)表達式會視為返回值瑟捣。

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
val sum = { x: Int, y: Int -> x + y }//可選標(biāo)注都留下

2.傳遞末尾的 lambda 表達式

在 Kotlin 中有?個約定:如果函數(shù)的最后?個參數(shù)是函數(shù),那么作為相應(yīng)參數(shù)傳入的 lambda 表達式可以放在圓括號之外,這種語法也稱為拖尾 lambda 表達式栅干。

val product = items.fold(1) { acc, e -> acc * e }

如果該 lambda 表達式是調(diào)用時唯?的參數(shù)迈套,那么圓括號可以完全省略:

run { println("...") }

3.it:單個參數(shù)的隱式名稱

如果編譯器自己可以識別出簽名,也可以不用聲明唯?的參數(shù)并忽略 -> 碱鳞。該參數(shù)會隱式聲明為 it:

ints.filter { it > 0 } // 這個字?值是“(it: Int) -> Boolean”類型的

4.從 lambda 表達式中返回?個值

使用返回標(biāo)簽語法從 lambda 顯式返回?個值桑李。否則,將隱式返回最后?個表達式的值。

ints.filter {
    val shouldFilter = it > 0
    shouldFilter
}
ints.filter {
    val shouldFilter = it > 0
    return@filter shouldFilter
}

搭配圓括號可外傳遞函數(shù)類型參數(shù)lambda表達式,可支持鏈?zhǔn)骄幊蹋↙INQ)語法:

strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }

5.下劃線用于未使用的變量

如果 lambda 表達式的參數(shù)未使用芙扎,那么可以用下劃線取代其名稱:

map.forEach { _, value -> println("$value!") }

6.在 lambda 表達式中解構(gòu)

你可以對 lambda 表達式參數(shù)使?解構(gòu)聲明語法。如果 lambda 表達式具有 Pair 類型(或者 Map.Entry 或任何其他具有相應(yīng) componentN 函數(shù)的類型)的參數(shù)填大,那么可以通過將它們放在括號中來引?多個新參數(shù) 來取代單個新參數(shù):

map.mapValues { entry -> "${entry.value}!" } 
map.mapValues { (key, value) -> "$value!" }

7.匿名函數(shù)

需要顯示指定函數(shù)返回類型可以使用匿名函數(shù)戒洼。看起來非常像?個常規(guī)函數(shù)聲明允华,除了其名稱省略了圈浇。其函數(shù)體可以是表達式或代碼塊:

//表達式
fun(x: Int, y: Int): Int = x + y
//代碼塊
fun(x: Int, y: Int): Int { 
    return x + y 
}

匿名函數(shù)的返回類型推斷機制與正常函數(shù)?樣:對于具有表達式函數(shù)體的匿名函數(shù)將?動推斷返回類型,?具 有代碼塊函數(shù)體的返回類型必須顯式指定(或者已假定為 Unit )靴寂。

匿名函數(shù)和Lambda的區(qū)別:

  • 匿名函數(shù)參數(shù)總是在括號內(nèi)傳遞磷蜀。允許將函數(shù)留在圓括號外的簡寫語法僅適?于 lambda 表達式。
  • Lambda表達式與匿名函數(shù)之間的另?個區(qū)別是非局部返回的行為百炬。?個不帶標(biāo)簽的 return 語句總是在用fun 關(guān)鍵字聲明的函數(shù)中返回褐隆。這意味著 lambda 表達式中的 return 將從包含它的函數(shù)返回,而匿名函數(shù)中 的 return 將從匿名函數(shù)自身返回剖踊。

8.閉包

Lambda 表達式或者匿名函數(shù)(以及局部函數(shù)和對象表達式)可以訪問其 閉包 庶弃,即在外部作?域中聲明的變 量。在 lambda 表達式中可以修改閉包中捕獲的變量:

var sum = 0
ints.filter { it > 0 }.forEach {
    sum += it
}
print (sum)

9.帶有接收者的函數(shù)字面值

帶有接收者的函數(shù)類型德澈,例如 A.(B) -> C 歇攻,可以用特殊形式的函數(shù)字面值實例化—— 帶有接收者的函數(shù)字面值。
在這樣的函數(shù)字?值內(nèi)部梆造,傳給調(diào)?的接收者對象成為隱式的this缴守,以便訪問接收者對象的成員而無需任何額外的限定符,亦可使用 this 表達式 訪問接收者對象镇辉。

val sum: Int.(Int) -> Int = { other -> plus(other) }

匿名函數(shù)語法允許你直接指定函數(shù)字?值的接收者類型

val sum = fun Int.(other: Int): Int = this + other
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屡穗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子忽肛,更是在濱河造成了極大的恐慌鸡捐,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麻裁,死亡現(xiàn)場離奇詭異箍镜,居然都是意外死亡,警方通過查閱死者的電腦和手機煎源,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門色迂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人手销,你說我怎么就攤上這事歇僧。” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵诈悍,是天一觀的道長祸轮。 經(jīng)常有香客問我,道長侥钳,這世上最難降的妖魔是什么适袜? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮舷夺,結(jié)果婚禮上苦酱,老公的妹妹穿的比我還像新娘。我一直安慰自己给猾,他們只是感情好疫萤,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著敢伸,像睡著了一般扯饶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上池颈,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天帝际,我揣著相機與錄音,去河邊找鬼饶辙。 笑死蹲诀,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弃揽。 我是一名探鬼主播脯爪,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼矿微!你這毒婦竟也來了痕慢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤涌矢,失蹤者是張志新(化名)和其女友劉穎掖举,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娜庇,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡塔次,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年吓肋,在試婚紗的時候發(fā)現(xiàn)自己被綠了掂名。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡棚壁,死狀恐怖匕得,靈堂內(nèi)的尸體忽然破棺而出继榆,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布略吨,位于F島的核電站集币,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏翠忠。R本人自食惡果不足惜鞠苟,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望负间。 院中可真熱鬧,春花似錦姜凄、人聲如沸政溃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽董虱。三九已至,卻和暖如春申鱼,著一層夾襖步出監(jiān)牢的瞬間愤诱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工捐友, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淫半,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓匣砖,卻偏偏與公主長得像科吭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子猴鲫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容