Kotlin:高階函數(shù)與 Lambda 表達(dá)式(四)

本篇內(nèi)容清單如下:

  • 高階函數(shù)
  • 函數(shù)類型
  • Lambda 表達(dá)式
  • 匿名函數(shù)
  • 閉包
  • 內(nèi)聯(lián)函數(shù)

Kotlin 函數(shù)使用場景:

  • 存儲在變量 與 數(shù)據(jù)結(jié)構(gòu)中选泻;
  • 作為 參數(shù) 傳遞給其他 高階函數(shù)蚕涤;
  • 從其他高階函數(shù)返回滔驾。

也即是可以像操作 變量 一樣操作 函數(shù)俺抽。

作為一門靜態(tài)語言柔逼,Kotlin 使用一系列 函數(shù)類型 來表示 函數(shù)活烙,并提供一組特定的語言結(jié)構(gòu)储耐,如 lambda 表達(dá)式钝荡。

1. 高階函數(shù)

  • 定義:將函數(shù)用作 參數(shù) 或 返回值 的函數(shù)街立。

2. 函數(shù)類型

  • 類似 (Int) -> String 的一系列 函數(shù)類型 來處理函數(shù)的聲明:val onClick: () -> Unit = ......

這些類型具有同 函數(shù)簽名 對應(yīng)的特殊表示法埠通,即其 參數(shù)和返回值:

  • 函數(shù)類型:(A, B) -> C赎离,均有 () 括起來的 參數(shù)列表 與 一個(gè)返回類型。參數(shù)類型列表可為空:() -> C 端辱。Unit 返回類型不可省略梁剔。
  • 函數(shù)類型 可有一個(gè)額外的 接收者 類型虽画,表示為:類型 A.(B) -> C ,表示在 A 的接收者對象上 傳遞一個(gè) B 類型參數(shù)餅干返回一個(gè) C 類型的值荣病。[沒明白 接收者對象 码撰??个盆?]
  • 掛起函數(shù) 屬于特殊種類的函數(shù)類型脖岛,表示法中有一個(gè) suspend 修飾符,如:suspend () -> Unitsuspend A.(B) -> C 颊亮。

函數(shù)類型表示法可以選擇性地加上參數(shù)名 x, y:(x: Int, y: Int) -> Point 柴梆。這些參數(shù)名稱可用于 表明參數(shù)的含義(代碼易讀)。

Tips:

  • 若需將 函數(shù)類型 指定為 可空终惑,可使用圓括號:((Int, Int) -> Int)?绍在。
  • 函數(shù)類型 可用圓括號進(jìn)行結(jié)合:(Int) -> ((Int) -> Unit)
  • 箭頭是右結(jié)合雹有,(Int) -> (Int) -> Unit 等價(jià)于 上述揣苏,但不等價(jià)于 ((Int) -> (Int)) -> Unit

使用 類型別名 給函數(shù)起一個(gè)別稱:

typealias ClickHandler = (Button, ClickEvent) -> Unit

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

有幾種方法可獲得函數(shù)類型的實(shí)例。

方式一:使用 函數(shù)字面值的代碼塊件舵,采用以下形式之一:

  • lambda 表達(dá)式{ a, b -> a + b }
  • 匿名函數(shù)fun(s: String): Int { return s.toIntOrNull() ?: 0 }
    備注:帶有接收者的函數(shù)字面值 可用作 帶有接收者的函數(shù)類型的值卸察。

方式二:使用 已有聲明的可調(diào)用引用:

  • 頂層、局部铅祸、成員坑质、擴(kuò)展函數(shù):::isOddString::toInt
  • 頂層临梗、成員涡扼、擴(kuò)展屬性:List<Int>::size
  • 構(gòu)造函數(shù):::Regex
    備注:包括 指向特定實(shí)例成員的 綁定的可調(diào)用引用foo::toString 。(這里的概念有點(diǎn)生盟庞,不態(tài)理解3曰Α!J膊)

方式三:使用 實(shí)現(xiàn)函數(shù)類型接口 的自定義類的實(shí)例:

class IntTransformer: (Int) -> Int {
    override operator fun invoke(x: Int): Int = TODO()
}

val intFun: (Int) -> Int - IntTransformer()  // 函數(shù)類型票彪,可以作為接口被類實(shí)現(xiàn),創(chuàng)建的類實(shí)例 為 函數(shù)類型 實(shí)例不狮。

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

  • 獲取 函數(shù)類型的值:invole(...) 操作符 調(diào)用:f.invoke(x) 或 直接 f(x) 降铸。
    fun demo02() {
        val strPlus: (String, String) -> String = String::plus
        val intPlus: Int.(Int) -> Int = Int::plus  // 帶有接收者 的函數(shù)類型

        println(strPlus.invoke("<-", "->"))
        println(strPlus("Hello ", "world!"))

        println(intPlus.invoke(1, 1))
        println(intPlus(1, 2))
        println(2.intPlus(3)) // 類擴(kuò)展調(diào)用
    }

5. Lambda 表達(dá)式

lambda 表示式 與 匿名函數(shù) 是 “函數(shù)字面值”,即 未聲明的函數(shù)摇零,可作為 表達(dá)式 傳遞推掸。

5.1 Lambda 表達(dá)式語法

完整語法形式:

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y}
// 省略 函數(shù)類型 寫法
val sum1 = { x: Int, y: Int -> x + y}
  • lambda 表達(dá)式 總是在 {} 中;
  • 完整語法形式 的 參數(shù)聲明是放在{}內(nèi),并有可選的類型標(biāo)注谅畅,函數(shù)體在 -> 符號之后登渣。
  • 若推斷出 lambda 的返回類型不是 Unit,則其主體中的最后一個(gè) 表達(dá)式 會(huì)作為返回值毡泻。
5.2 傳遞末尾的 lambda 表達(dá)式
  • 若函數(shù)的最后一個(gè)參數(shù)是 函數(shù)胜茧,則傳遞 lambda 表達(dá)式時(shí)可以放在圓括號之外:
val product = items.fold(1) { acc, e -> acc * e }

上述語法稱為「拖尾 lambda 表達(dá)式」

  • 若該 lambda 表達(dá)式是調(diào)用時(shí)唯一的參數(shù)牙捉,則圓括號可以完全省略:run { println("...") }
5.3 it: 單個(gè)參數(shù)的隱式名稱
  • 一個(gè) lambda 只有一個(gè)參數(shù)是很常見的敬飒。
    如果編譯期可以識別簽名邪铲,也可以不聲明唯一的參數(shù)并忽略 -> 。該參數(shù)會(huì)隱式 聲明為 it :
val ints = intArrayOf(1, 2)
ints.filter {
      val shouldFilter = it > 0  // 隱式返回最后一個(gè)表達(dá)式的值
      shouldFilter
}

6. 匿名函數(shù)

定義:

  • 省略了函數(shù)名稱
  • 參數(shù) 和 返回類型 同常規(guī)函數(shù)一致无拗,能根據(jù)上下文推斷出的參數(shù)類型可省略
  • 返回類型機(jī)制:同正常函數(shù)一致带到。1)對于具有 表達(dá)式函數(shù)體 的匿名函數(shù)將自動(dòng)過推斷返回類型;2)對具有代碼塊函數(shù)體的返回類型 必須顯式制定個(gè)(或假定為 Unit)英染。

形式:fun(x: Int, y: Int): Int = x + y

Tips:匿名函數(shù)參數(shù) 總是在括號內(nèi)傳遞揽惹。將函數(shù) 留在圓括號外的簡寫語法 僅適用于 lambda 表達(dá)式。

1)VS lambda 表達(dá)式:

  • lambda 缺少 指定函數(shù)的返回類型 的能力四康。
    大多數(shù)情況非必要搪搏,因?yàn)榉祷仡愋涂勺詣?dòng)推斷。如果要顯式指定闪金,可使用另一種語法:匿名函數(shù)疯溺。
    -「非局部返回」的行為。一個(gè)不帶標(biāo)簽的 return 語句總是用 fun 關(guān)鍵字聲明的函數(shù)中返回哎垦。
    lambda 表達(dá)式中的 return 將從包含它的函數(shù)返回囱嫩;而匿名函數(shù)中的 return 將從匿名函數(shù)自身返回。

7. 閉包

定義:在外部作用域中聲明的變量漏设。

  • lambda 表達(dá)式 和 匿名函數(shù)(局部函數(shù)墨闲、對象表達(dá)式),均可訪問 閉包郑口。
  • 在 lambda 表達(dá)式中鸳碧,可以修改 閉包中捕獲的變量。
    fun demo04() {
        var sum = 0
        var ints = intArrayOf(1, 2, 3)
        ints.filter { it > 0 }.forEach { sum += it }
        println(sum)
    }

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

定義:類型 A.(B) -> C 這種形式 的函數(shù)字面值實(shí)例化犬性。

    fun List<String>.demo05(words: MutableList<String>, maxLen: Int) {
        this.filter {
            it.length <= maxLen
        }
        val articles = setOf("a", "A", "an", "An", "the", "The")
        words -= articles
    }

    fun callDemo01() {
        val words = "A long time ago in a galaxy far far away".split(" ")
        val shortWords = mutableListOf<String>()
        words.demo05(shortWords, 3)  // 在一個(gè)類定義另一個(gè)類的方法杆兵,并可直接調(diào)用
        println(shortWords)
    }

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

TODO

待理解概念與使用場景:

  • 帶有接收者的函數(shù)字面值
  • 內(nèi)聯(lián)函數(shù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仔夺,隨后出現(xiàn)的幾起案子琐脏,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件日裙,死亡現(xiàn)場離奇詭異吹艇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)昂拂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門受神,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人格侯,你說我怎么就攤上這事鼻听。” “怎么了联四?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵撑碴,是天一觀的道長。 經(jīng)常有香客問我朝墩,道長醉拓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任收苏,我火速辦了婚禮亿卤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹿霸。我一直安慰自己排吴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布懦鼠。 她就那樣靜靜地躺著傍念,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葛闷。 梳的紋絲不亂的頭發(fā)上憋槐,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音淑趾,去河邊找鬼阳仔。 笑死棘催,一個(gè)胖子當(dāng)著我的面吹牛盾计,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播集峦,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼延蟹,長吁一口氣:“原來是場噩夢啊……” “哼评矩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阱飘,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤斥杜,失蹤者是張志新(化名)和其女友劉穎虱颗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔗喂,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忘渔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缰儿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畦粮。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖乖阵,靈堂內(nèi)的尸體忽然破棺而出宣赔,到底是詐尸還是另有隱情,我是刑警寧澤瞪浸,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布儒将,位于F島的核電站,受9級特大地震影響默终,放射性物質(zhì)發(fā)生泄漏椅棺。R本人自食惡果不足惜犁罩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一齐蔽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧床估,春花似錦含滴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至递胧,卻和暖如春碑韵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缎脾。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工祝闻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遗菠。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓联喘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辙纬。 傳聞我的和親對象是個(gè)殘疾皇子豁遭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

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