1. 程式人生 > >Kotlin程式設計之高階函式,Lambda表示式,匿名函式

Kotlin程式設計之高階函式,Lambda表示式,匿名函式

Kotlin程式設計相關知識點介紹

高階函式

A higher-order function is a function that takes functions as parameters, or returns a function

高階函式具備以下特徵:

  • 接受一個函式作為引數
  • 或者返回一個函式

為List擴充套件一個函式,使用高階函式用法,編寫程式碼如下:

package com.xingen.kotlin.day201761

fun main(args: Array<String>) {

    var oldlist = arrayListOf<Int>(1
, 2, 3) println("原本資料是 $oldlist") /** * 面向函式:類似Java8中lambda表示式,傳入一個函式物件。 * lambda表示式的形式: { 引數名 -> 函式體 } * 這裡的item是引數,返回值item+3是函式體 * * 注意點:List.transform()是帶有括號的, * 但是在Kotlin程式設計中方法最後一個引數是函式,且傳入lambda表示式作為引數的話,函式的括號可以省略, * 因此,是這裡是List.transform{ lambda表示式 } */
var newList = oldlist.transform { item -> item + 3 } println("轉換後的新資料是 $newList") } /** * 給List 類定義一個擴充套件函式transform() , * 然後使用高階函式,其中方法引數是一個函式 */ fun <T, R> List<T>.transform(transformFun: (T) -> R): List<R> { //建立一個新的List物件,用於裝載轉換後的item var result = arrayListOf<R>() /** * 類似java中增強for迴圈。 * 擴充套件函式中的this指向接受者物件,也就是該呼叫擴充套件函式的物件 */
for (item in this) { var newItem = transformFun(item)// 呼叫引數中的函式方法進行轉換新的item. result.add(newItem) } return result }

輸出結果:

原本資料是 [1, 2, 3]
轉換後的新資料是 [4, 5, 6]

可知:

  • lambda表示式的形式:{ 引數名 -> 函式體 }

  • 但是在Kotlin程式設計中方法最後一個引數是函式,且使用lambda表示式作為引數傳入,方法的括號可以省略。例如,上面的程式碼:List.transform{ lambda表示式 }

Lambda表示式

一個Lambda表示式是一個字面函式,即一個未宣告的函式,會以表示式的形式傳遞。

 oldlist.transform { item -> item + 3 }

上面的Lambda表示式,實際上也是一個字面函式,等同於以下函式:

fun <T> transformFun(item: T):T{
    return item+3
}

函式型別

接收一個函式作為引數,為引數指定函式型別。例如:

fun <T, R> List<T>.transform(transformFun: (T) -> R): List<R> {
    //建立一個新的List物件,用於裝載轉換後的item
    var result = arrayListOf<R>()
    /**
     * 類似java中增強for迴圈。
     * 擴充套件函式中的this指向接受者物件,也就是該呼叫擴充套件函式的物件
     */
    for (item in this) {
        var newItem = transformFun(item)// 呼叫引數中的函式方法進行轉換新的item.
        result.add(newItem)
    }
    return result
}

引數transformFun的型別是(T) -> R,解讀函式型別的意思:傳遞一個引數,返回一個相同型別的返回值。

transformFun引數是一個函式,因此作為一個函式來使用,傳遞一個T型別的引數,會返回同類型的返回值。

Lambda表示式語法

第一種語法:

/**
 * 一個完成的Lambda表示式
 */
var total1={x:Int,y:Int->x+y}

第二種,含可選標註的語法

/**
 * 帶有可選標註的Lambda表示式,使文件化每個引數的含義
 * 
 * var total2:(Int,Int)->Int=...這種函式型別,可理解為一個函式中接受一個函式做為引數時候,引數的宣告形式。
 */
var total2:(Int,Int)->Int={  x,y   ->   x+y   }

在Main函式中呼叫:

package com.xingen.kotlin.day201761

fun main(args: Array<String>) {

    println(  total1(1,2)  )
    println(total2(1,2))
}

輸出結果如下:

3
3

可知:

  • lambda 表示式總是被大括號括著, 完整語法形式的引數宣告放在括號內,並有可選的型別標註, 函式體跟在一個 -> 符號之後。

  • 如果推斷出的該 lambda 的返回型別不是 Unit,那麼該 lambda 主體中的最後一個(或可能是單個)表示式會視為返回值

匿名函式

大多數情況下,Lambda表示式是不指定函式的返回型別,因為可以自動推斷出來。當需要顯式指定函式的返回型別,需要使用到:匿名函式

編寫一個匿名函式的案例:

package com.xingen.kotlin.day201761

fun main(args: Array<String>) {

    println(test3(1,2))
    println(test4(1,2))
    println(test5(1,2))
}

/**
 * 匿名函式,沒有名字,其他語法和常規函式類似
 *
 * 宣告一個匿名函式,這裡用表示式來表示函式體
 */
var test3= fun(x:Int,y:Int):Int=x+y
/**
 * 宣告一個匿名函式,這裡用程式碼塊來表示函式體
 */
var test4= fun(x:Int,y:Int):Int{
    return  x+y
}
/**
 * 宣告一個匿名函式,當返回值型別可以推斷出,可以省略
 */
var test5= fun(x:Int,y:Int)=x+y

輸出結果如下:

3
3
3

可知:

  • 匿名函式,沒有名字,其他語法和常規函式類似,例如:當返回值型別可以推斷出,可以省略

除了以上提到的顯式指定函式的返回型別區別外,Lambda表示式和匿名函式的另外一個區別:

一個不帶標籤的 return 語句 總是在用 fun 關鍵字宣告的函式中返回。這意味著 lambda 表示式中的 return 將從包含它的函式返回,而匿名函式中的 return 將從匿名函式自身返回。

閉包

閉包是指在外部作用域中宣告的變數。與Java不同的是,在Kotlin程式設計中,可以修改閉包中捕獲的變數。

可以訪問閉包的:

  • Lambda表示式
  • 匿名函式
  • 區域性函式(函式內包含函式)
  • 物件表示式

例如,案例:

package com.xingen.kotlin.day201761

fun main(args: Array<String>) {

    println(i)
    test4(1,2)
    println(1)
}
var i=0
/**
 * 宣告一個匿名函式,這裡用程式碼塊來表示函式體
 */
var test4= fun(x:Int,y:Int):Int{
    i++ //外部的變數,且修改
    return  x+y
}

輸出結果:

0
1

帶有接受者的字面函式

Kotlin 提供了使用指定的 接收者物件 呼叫函式字面值的功能。 在函式字面值的函式體中,可以呼叫該接收者物件上的方法而無需任何額外的限定符。 這類似於擴充套件函式,它允你在函式體內訪問接收者物件的成員。

package com.xingen.kotlin.day201761

fun main(args: Array<String>) {

    //類似擴充套件函式的用法,用例項物件來呼叫
    println( 1.test6(2) )
    println( 1.test7(2) )
}
/***
 * 帶有接受者的Lambda表示式
 *
 * 這裡的函式型別是一個帶有接受者的型別:
 *
 * test6:Int.(other:Int)->Int
 */
var test6:Int.(other:Int)->Int={ other->other+1}
/**
 * 帶有接受者的匿名函式
 *
 * 用表示式表示式函式體:
 *
 * var test7=fun Int.(other:Int):Int=this+other
 *
 * 這裡, 用程式碼塊表示函式體,來宣告一個匿名函式,最後賦給一個變數
 */
var test7=fun Int.(other:Int):Int{
    return this+other   //this是指向接受者的物件
}

輸出結果如下:

3
3