本篇內(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 () -> Unit
或suspend 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ù):
::isOdd
、String::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ù)