頭等函式(first-class function)是指在程式語言中,函式被當作頭等公民。這意味著,函式可以作為別的函式的引數、函式的返回值,賦值給變數或儲存在資料結構中。 kotlin 函式都是頭等的
,這意味著它們可以儲存在變數與資料結構中、作為引數傳遞給其他高階函式以及從其他高階函式返回。可以像操作任何其他非函式值一樣操作函式。
高階函式是將函式用作引數或返回值的函式。
比如集合的[函式式風格的fold
, 它接受乙個初始累積值與乙個接合函式,並通過將當前累積值與每個集合元素連續接合起來代入累積值來構建返回值,fold
高階函式定義如下:
fun collection.fold(
initial: r,
combine: (acc: r, nextelement: t) -> r
): r
return accumulator
}
在上述**中,引數combine
具有函式型別(r, t) -> r,因此
fold接受乙個函式作為引數, 該函式接受型別分別為
r與
t的兩個引數並返回乙個
r型別的值。 在 *for*-迴圈內部呼叫該函式,然後將其返回值賦值給
accumulator。為了呼叫
fold`,需要傳給它乙個函式型別的例項作為引數,而在高階函式呼叫處,lambda 表達 式廣泛用於此目的。
val items = listof(1, 2, 3, 4, 5)
// lambdas 表示式是花括號括起來的**塊。
items.fold(0, )
// lambda 表示式的引數型別是可選的,如果能夠推斷出來的話:
val joinedtostring = items.fold("elements:", )
// 函式引用也可以用於高階函式呼叫:
val product = items.fold(1, int::times)
執行結果:
acc = 0, i = 1, result = 1
acc = 1, i = 2, result = 3
acc = 3, i = 3, result = 6
acc = 6, i = 4, result = 10
acc = 10, i = 5, result = 15
joinedtostring = elements: 1 2 3 4 5
product = 120
kotlin 使用類似(int) -> string
的一系列函式型別來處理函式的宣告:val onclick: () -> unit = ……
。
這些型別具有與函式簽名相對應的特殊表示法,即它們的引數和返回值:
所有函式型別都有乙個圓括號括起來的引數型別列表以及乙個返回型別:(a, b) -> c
表示接受型別分別為a
與b
兩個引數並返回乙個c
型別值的函式型別。 引數型別列表可以為空,如() -> a
。unit
返回型別不可省略。
函式型別可以有乙個額外的接收者型別,它在表示法中的點之前指定: 型別a.(b) -> c
表示可以在a
的接收者物件上以乙個b
型別引數來呼叫並返回乙個c
型別值的函式。 帶有接收者的函式字面值通常與這些型別一起使用。
掛起函式屬於特殊種類的函式型別,它的表示法中有乙個 suspend 修飾符 ,例如suspend () -> unit
或者suspend a.(b) -> c
。
函式型別表示法可以選擇性地包含函式的引數名:(x: int, y: int) -> point
。 這些名稱可用於表明引數的含義。
獲得函式型別的例項有以下幾種方法:
使用函式字面值的**塊
lambda表示式:
匿名函式:fun(s: string): int
使用已有宣告的可呼叫引用
頂層、區域性、成員、擴充套件函式:::isodd
、string::toint
,
頂層、成員、擴充套件屬性:list::size
,
建構函式:::regex
使用實現函式型別介面的自定義類的例項:
class inttransformer: (int) -> int
val intfunction: (int) -> int = inttransformer()
函式型別的值可以通過其invoke(……)
操作符呼叫:f.invoke(x)
或者直接f(x)
。
如果該值具有接收者型別,那麼應該將接收者物件作為第乙個引數傳遞。 呼叫帶有接收者的函式型別值的另乙個方式是在其前面加上接收者物件, 就好比該值是乙個擴充套件函式:1.foo(2)
,
例如:
val stringplus: (string, string) -> string = string::plus
val intplus: int.(int) -> int = int::plus
println(stringplus.invoke("<-", "->"))
println(stringplus("hello, ", "world!"))
println(intplus.invoke(1, 1))
println(intplus(1, 2))
println(2.intplus(3)) // 類擴充套件呼叫
執行結果:
<-->
hello, world!23
5
lambda 表示式語法
lambda 表示式的完整語法形式如下:
val sum =
lambda 表示式總是括在花括號中, 完整語法形式的引數宣告放在花括號內,並有可選的型別標註, 函式體跟在乙個->
符號之後。如果推斷出的該 lambda 的返回型別不是unit
,那麼該 lambda 主體中的最後乙個(或可能是單個)表示式會視為返回值
如果我們把所有可選標註都留下,看起來如下:
val sum: (int, int) -> int =
當乙個 lambda 表示式只有乙個引數時,如果編譯器自己可以識別出簽名,也可以不用宣告唯一的引數並忽略->
。 該引數會隱式宣告為it
:
ints.filter // 這個字面值是「(it: int) -> boolean」型別的
如果 lambda 表示式的引數未使用,那麼可以用下劃線取代其名稱:
map.foreach
匿名函式
上面提供的 lambda 表示式語法缺少的乙個東西是指定函式的返回型別的能力。在大多數情況下,這是不必要的。因為返回型別可以自動推斷出來。然而,如果確實需要顯式指定,可以使用另一種語法: 匿名函式 。
fun(x: int, y: int): int = x + y
匿名函式看起來非常像乙個常規函式宣告,除了其名稱省略了。其函式體可以是表示式(如上所示)或**塊:
fun(x: int, y: int): int
引數和返回型別的指定方式與常規函式相同,除了能夠從上下文推斷出的引數型別可以省略:
ints.filter(fun(item) = item > 0)
匿名函式的返回型別推斷機制與正常函式一樣:對於具有表示式函式體的匿名函式將自動推斷返回型別,而具有**塊函式體的返回型別必須顯式指定(或者已假定為unit
)。
請注意,匿名函式引數總是在括號內傳遞。 允許將函式留在圓括號外的簡寫語法僅適用於 lambda 表示式。
lambda表示式與匿名函式之間的另乙個區別是非區域性返回的行為。乙個不帶標籤的 return 語句總是在用 fun 關鍵字宣告的函式中返回。這意味著 lambda 表示式中的 return 將從包含它的函式返回,而匿名函式中的 return 將從匿名函式自身返回。
Kotlin學習記錄7 初識繼承
open class animal open funprintinfo fungetgender string 1.該類要能被繼承需要使用open修飾符。2.能被子類覆蓋的方法需要使用open修飾。3.能被子類覆寫的屬性需要使用open修飾。class cat animal override fun...
Kotlin筆記(四)控制流
在 kotlin 中,if是乙個表示式,即它會返回乙個值 傳統用法 var max a if a b max b with else var max int if a b elseif的分支可以是 塊,最後的表示式作為該塊的值 作為表示式 注意if語句作為表示式必須有else val max if ...
Kotlin 四 委託 復合符號
1 在委託模式中,有兩個物件參與處理同乙個請求,接受請求的物件將請求委託給另乙個物件來處理。2 delegation類並沒有實現 idelegatelistener 中的 delegate 方法,而是通過by這個關鍵字,將本應該實現的方法委託給了bean,由bean來實現方法 委託屬性 定義乙個委託...