1. 函數(shù)類型
在Kotlin中,函數(shù)是一等公民(first class),這意味著函數(shù)可以被存儲在變量或者數(shù)據(jù)結(jié)構(gòu)中,它是有類型的。Kotlin使用函數(shù)類型來描述一個(gè)函數(shù)的具體類型。一個(gè)完整語法的函數(shù)類型如下:
(x:Int, y:Int) -> Int
其特點(diǎn)如下:
- 函數(shù)類型包括三部分,箭頭左側(cè)的是函數(shù)的參數(shù),描述了參數(shù)個(gè)數(shù)和類型,參數(shù)必須用小括號括起來;箭頭處于中間;箭頭右邊是函數(shù)返回值的類型。比如上述函數(shù)類型的入?yún)⑹莾蓚€(gè)Int型變量,返回值是Int型。注意如果返回值是Unit型時(shí),不能省略不寫。
- 函數(shù)參數(shù)的變量名可以省略不寫,例如上述示例可以簡寫為:
(Int, Int) -> Int
- 函數(shù)類型可以有一個(gè)額外的接收者類型,它的語法如下:
Int.(Int) -> Int
接收者類型在參數(shù)前,和參數(shù)所在的小括號用點(diǎn)連接。關(guān)于帶接收者的函數(shù)類型在之后會詳細(xì)講解。
2. 函數(shù)類型實(shí)例化
既然函數(shù)有類型,那函數(shù)類型變量的值是什么呢?這就涉及到函數(shù)類型的實(shí)例化。函數(shù)類型的實(shí)例化包括以下幾種常用方式。
a. lambda表達(dá)式:
{ i, j-> this + i + j }
b. 匿名函數(shù):
fun(s1: Int, s2: Int): Int { return 1}
- 使用一個(gè)已存在聲明的可調(diào)用引用:
a. 頂級,本地,成員或者擴(kuò)展函數(shù)。例如:String::toInt。
b. 頂級,成員,或者擴(kuò)展屬性:List::size。
c. 構(gòu)造函數(shù):::Regex。
- 使用實(shí)現(xiàn)了函數(shù)類型接口的自定義類的實(shí)例。例如:
class?IntTransformer:?(Int)?->?Int?{? override?operator?fun?invoke(x:?Int):?Int?=?TODO()?}?val?intFunction:?(Int)?->?Int?=?IntTransformer()
函數(shù)類型的值可以通過invoke操作符調(diào)用,以下是示例。
val stringPlus: (String, String) -> String = String::plusprintln(stringPlus.invoke(“”))println(stringPlus(“Hello, “, “world!”))
3. 函數(shù)字面值
函數(shù)字面值是指不聲明,而直接作為表達(dá)式傳遞的函數(shù)。它包括兩種,lambda表達(dá)式及匿名函數(shù)。
3.1 lambda表達(dá)式
lambda表達(dá)式的全語法形式如下:
val sum: (Int, Int) -> Int = {x: Int, y: Int -> x + y}
其特點(diǎn)如下:
- lambda表達(dá)式必須在大括號中。
- lambda表達(dá)式的參數(shù)列表在->左邊,參數(shù)類型是可選的,如果其類型可以推斷出來,則類型可以省略。例如上例可簡寫為:
val sum: (Int, Int) -> Int = {x, y -> x + y}
- 如果lambda表達(dá)式的返回值不是Unit,其最后一個(gè)表達(dá)式的值是返回值。例如以下表達(dá)式:
val sum: (Int, Int) -> Int = {x, y -> x + y x-y}
其返回值是x-y
Kotlin有一個(gè)約定:如果函數(shù)的最后一個(gè)參數(shù)是函數(shù),那么作為相應(yīng)參數(shù)傳入的lambda表達(dá)式可以放在圓括號之外。示例如下:
以lambda表達(dá)式作為參數(shù)的高階函數(shù)如下:
fun lambdaWrapper(labmda: (Int) -> Int) { labmda.invoke(1)}
其調(diào)用示例可以簡寫為:
fun lambdaTest() { lambdaWrapper() { it -> it+1 }}
如果lambda表達(dá)式是唯一的參數(shù),那其圓括號可以省略,示例如下:
fun lambdaTest() { lambdaWrapper{ it -> it+1 }}
由于本lambda表達(dá)式只有一個(gè)參數(shù),其可以隱式聲明為it,并去掉該參數(shù)的聲明和->。示例如下:
fun lambdaTest() { lambdaWrapper{ it+1 }}
自Kotlin1.1起,如果lambda表達(dá)式的參數(shù)未使用,那么可以用下劃線取代其名稱:
map.forEach { _, value -> println(“$value!”) }
3.2 匿名函數(shù)
lambda表達(dá)式不能顯示的指定返回值的類型。如果需要顯示指定返回值的類型,則需要使用匿名函數(shù)。匿名函數(shù)和普通函數(shù)非常類似,除了其函數(shù)名被省略。其示例如下:
fun(x: Int, y: Int): Int { return x + y}
匿名函數(shù)的參數(shù)和返回值類型的聲明與常規(guī)函數(shù)相同,同時(shí)類型如果可以推斷出來則可以省略。例如以下示例:
fun anonymousWrapper(labmda: (Int) -> Int) {????labmda.invoke(1)}fun anonymousTest() {????anonymousWrapper(fun (i: Int): Int {????????return ?i + 1????})}
anonymousTest中對匿名函數(shù)的調(diào)用是完整語法形態(tài),由于參數(shù)類型和返回值類型可以推斷,因此,其可以簡寫為
fun anonymousTest() { anonymousWrapper(fun (i) = i+1)}
請注意,匿名函數(shù)參數(shù)總是在括號內(nèi)傳遞。 允許將函數(shù)留在圓括號外的簡寫語法僅適用于lambda表達(dá)式。
lambda表達(dá)式與匿名函數(shù)之間的另一個(gè)區(qū)別是非局部返回的行為。一個(gè)不帶標(biāo)簽的return語句總是在用fun關(guān)鍵字聲明的函數(shù)中返回。這意味著lambda表達(dá)式中的return將從包含它的函數(shù)返回,而匿名函數(shù)中的return將從匿名函數(shù)自身返回。