Kotlin語言基礎筆記
Kotlin流程控制語句筆記
Kotlin操作符重載與中綴表示法筆記
Kotlin擴展函數(shù)和擴展屬性筆記
Kotlin空指針安全(null-safety)筆記
Kotlin類型系統(tǒng)筆記
Kotlin面向?qū)ο缶幊坦P記
Kotlin委托(Delegation)筆記
Kotlin泛型型筆記
Kotlin函數(shù)式編程筆記
Kotlin與Java互操作筆記
Kotlin協(xié)程筆記
就像在Java的世界中,一切皆是對象。那么在函數(shù)式編程中當然一切皆是函數(shù)。函數(shù)式編程感覺像返璞歸真,現(xiàn)在又火了起來。Kotlin作為一位這幾年才出現(xiàn)的語言必然會支持函數(shù)式編程。在Kotlin中函數(shù)式一等公民,地位和對象一樣高,你可以在方法中輸入函數(shù),也可以返回函數(shù)。相對于Scala的學院派風格,Kotlin則是純的的工程派:實用性、簡潔性上都要比Scala要好。怪不得我當年看Scala中感覺好像門檻有點高,上手比較難。
1. 高階函數(shù)
高階函數(shù)是將函數(shù)用作參數(shù)或者返回值的函數(shù)。Kotlin的Collection類型中有大量的這種高階函數(shù),例如:Iterable的filter函數(shù)
其中
predicate: (T) -> Boolean
定義了一個函數(shù)變量,變量名是predicate,類型是(T) -> Boolean
這樣一個函數(shù)。這個函數(shù)表示輸入?yún)?shù)是T類型,輸出Boolean類型。那我們來定義這樣一個函數(shù),然后調(diào)用高階函數(shù)Iterable.filter
。
fun isLargeThanFive(x: Int): Boolean = x > 5
fun main(args: Array<String>) {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
println(numbers.filter(::isLargeThanFive)) //打印[6, 7, 8]
}
注意:我們使用::
來引用一個函數(shù)。
2. 匿名函數(shù)
匿名函數(shù),其實就是沒有函數(shù)名的函數(shù)。我們也可以使用匿名函數(shù)來實現(xiàn)上面的代碼:
fun main(args: Array<String>) {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
println(numbers.filter(
fun (x: Int):Boolean {
return x > 5
}
)
)
//or 寫成一行
//println(numbers.filter(fun(x: Int) = x > 5))
}
3. Lambda表達式
我們也可以使用更簡單Lambda表達式來實現(xiàn):
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
numbers.filter({ it > 5 })
//or 這樣
numbers.filter { it > 5 }
Lambda表達式是這樣定義的:
- lambda 表達式總是括在花括號中。
- 其參數(shù)(如果有的話)在 -> 之前聲明(參數(shù)類型可以省略)。
- 函數(shù)體(如果存在的話)在 -> 后面。
- 如果lambda表達式是該調(diào)用的唯一函數(shù),則調(diào)用中的圓括號可以省略。
- 如果函數(shù)的最后一個參數(shù)是一個函數(shù),并且你傳遞一個 lambda 表達式作為相應的參數(shù),你可以在圓括號之外指定它。
對于最后一點,我們可以看看Iterable.elementAtOrElse
方法:
這個方法是返回第index元素,如果不存在的話返回(Int) -> T的函數(shù)值,函數(shù)參數(shù)是index,返回T類型。我們可以看看如何調(diào)用:
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
println(numbers.elementAtOrElse(10, { 100}))
//或者可以這樣。
println(numbers.elementAtOrElse(10) {100})
我們現(xiàn)在來定義一個兩個參數(shù)的lambda表達式:
val max = { x: Int, y: Int -> if (x > y) x else y }
//下面這句等同于上面這句代碼。
//val max: (Int, Int) -> Int = { x: Int, y: Int -> if (x > y) x else y }
println(max(1, 2))
更復雜的,lambda表達式還可以返回一個lambda表達式:
val sum = { x: Int -> {y:Int -> x+y } }
println(sum) //打印(kotlin.Int) -> (kotlin.Int) -> kotlin.Int
println(sum(2)(1)) //打印3
3.1 it單個參數(shù)的隱私名稱
當lambda表達式只有一個參數(shù)時,那么它的聲明可以省略(包括->
)。可以用it代表lambda唯一的參數(shù)。
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
numbers.filter({ it > 5 })
//or 這樣
numbers.filter { it > 5 }
3.2 下劃線用于未使用的變量(1.1版本起)
如果 lambda 表達式的參數(shù)未使用,那么可以用下劃線取代其名稱:
map.forEach { _, value -> println("$value!") }
4. 閉包
Lambda 表達式或者匿名函數(shù),以及局部函數(shù)和對象表達式(object declarations)可以訪問其 閉包,即在外部作用域中聲明的變量。 與 Java 不同的是可以修改閉包中捕獲的變量:
fun main(args: Array<String>) {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
var sum = 0
numbers.filter { it > 5 }.forEach { sum += it }
println(sum) //打印21
}
5. 帶接收者的函數(shù)字面值
使用匿名函數(shù)的語法,我們可以直接指定函數(shù)字面值的接收者類型。
val sum = fun Int.(other: Int): Int = this + other
println(1.sum(1)) 打印2
當接收者類型可以從上下文推斷時,lambda 表達式可以用作帶接收者的函數(shù)字面值。
class HTML {
fun body() {
println("HTML BODY")
}
}
fun html(init: HTML.() -> Unit): HTML { // HTML.()中的HTML是接受者類型
val html = HTML() // 創(chuàng)建接收者對象
html.init() // 將該接收者對象傳給該 lambda
return html
}
fun main(args: Array<String>) {
html{
body()
} //打印HTML BODY
}
這個特性可以讓我們構(gòu)建DSL語言,類似安卓中build.gradle中的語法。