Kotlin—函數式編程 (一)

今天開始學習Kotlin的第二大思想,函數式編程。

函數式編程在中一切都是函數。

核心概念:

  1. 函數和其它數據類型是一樣的,可以作爲其它函數的參數傳入,也可做爲函數的返回值。
  2. 使用表達式,不用語句。
  3. 高階函數:一個函數可做爲另一個函數的參數和返回值
  4. 無副作用:函數執行過程會返回一個結果,不會修改外部變量

高階函數

函數式編程的關鍵是支持高階函數,就是說一個函數可以做爲另一個函數參數或者返回值。

函數類型

先看一下什麼是函數類型,在Kotlin中每個函數都有一個類型,稱爲函數類型,函數類型是中數據類型

fun main(args: Array<String>) {
    var a: (Int, Int) -> Int = ::add  
    println(a(1, 2))
}

fun add(a: Int, b: Int): Int {
    return a + b
}

第三行中的 (Int, Int) -> Int 就是函數類型,意思聲明一個屬性類型爲函數類型。

(Int, Int) 說明這個函數要滿足,兩個Int參數  -> Int 是指返回值是Int類型。

(參數:參數類型)->返回值類型  參數可以有多個,也可以沒有就省略。

fun main(args: Array<String>) {
    var a: () -> Unit = ::test
    println(a())

}


fun test() {
    println("無返回值的函數")
}

這是無返回值的函數,如果,不學返回值默認爲無返回值。

函數字面量

函數類型可以聲明的變量就是函數字面量

函數字面量可以接收三種類型的數據類型。

  • 函數的引用
  • 匿名函數
  • Lambda表達式
fun main(args: Array<String>) {
    var a = ::add             //函數的引用
    var b = ::sub             //函數的引用
    println(a(1, 1))  
    println(b(2, 1))
    println(ride(1, 10))      //匿名函數
    println(divide(10, 1))    //Lambda表達式
}

fun add(a: Int, b: Int): Int {
    return a + b
}

fun sub(a: Int, b: Int): Int {
    return a - b
}

var ride = fun(a: Int, b: Int): Int {
    return a * b
}
var divide = { a: Int, b: Int -> a / b }

函數返回值

把一個函數做另一個函數的返回值使用,這個函數就是高階函數。

fun main(args: Array<String>) {

    val getfun = getfun("add")
    println(getfun(1, 2))
}

fun getfun(string: String): (Int, Int) -> Int {
    var a: (Int, Int) -> Int
    when (string) {
        "add" -> a = ::add
        else -> {
            a = ::sum
        }
    }

    return a
}

fun add(a: Int, b: Int): Int {
    return a + b
}

fun sum(a: Int, b: Int): Int {
    return a + b
}

函數參數

fun main(args: Array<String>) {

    setFun(add(1, 2))
}

fun setFun(funName: (Int, Int) -> Int) {
    println(funName)
}

fun add(a: Int, b: Int): (Int, Int) -> Int {
    return fun(a: Int, b: Int): Int {
        return a + b
    }
}

Lambda表達式

Lambda表達式是一種匿名函數,它可以做表達式、函數、參數和返回值用

剛纔的案例可以改爲Lambda表達式用

fun main(args: Array<String>) {

    setFun({ a, b -> a + b })
}

fun setFun(funName: (Int, Int) -> Int) {
    println(funName)
}

fun add(a: Int, b: Int): (Int, Int) -> Int {
    return { a, b -> a + b }
}

Lambda  怎麼寫

{參數列表:參數類型->Lambda體}

或者在簡寫{參數列表->Lambda體}

不寫參數類型,因爲有時候可以自動推到類型Lambda

尾隨Lambda

fun main(args: Array<String>) {

    setFun() { a, b -> a + b }
}

fun setFun(funName: (Int, Int) -> Int) {
    println(funName(1, 2))
}

如果函數最後一個是Lambda的時候就可以放到小括號外面

省略參數聲明

fun main(args: Array<String>) {
    getString("abc", { it.reversed() })

}

fun getString(s: String, funName: (String) -> String) {
    println(funName(s))
}

Lambda中的return語句

在Lambda直接使用return會使函數直接退出,而不是退出Lambda表達式。

fun main(args: Array<String>) {
    getString("aaAbbb")
}

fun getString(s: String) {
    s.forEach {
        println(it)
        if (it == 'A') {
            return
        }
        println("Lambda")
    }
    println("函數退出")
}

沒有打印出 函數退出,證明它直接結束了函數,而非Lambda表達式。

我們用之前學的知識改一下

fun main(args: Array<String>) {
    getString("aaAbbb")
}

fun getString(s: String) {
    forEach@ s.forEach {
        println(it)
        if (it == 'A') {
            return@forEach
        }
        println("Lambda")
    }
    println("函數退出")
}

結果:

這次看到了,說明是結束的Lambda表達式

閉包與捕獲變量

閉包使一種特殊的函數,它可以訪問函數體之外的變量

fun main(args: Array<String>) {
    val test = test()
    println(test(10))
    println(test(10))
    println(test(10))
}

fun test(): (Int) -> Int {
    var vaule = 10

    fun add(a: Int): Int {
        vaule += a
        return vaule
    }
    return ::add
}

結果:

可以看到,結果是累加了,這就是閉包捕獲變量。這些變量會被保存到一個特殊的容器中,即使超過作用域在閉包體中也可以訪問到。

內聯函數

待補充

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章