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