Kotlin 的High-order functions 與 Lambdas
Kotlin 的 function是屬於一級函式(first-class function),意思是 function可以像變數一樣被使用,也能在一個high-order-function 中被當作參數來傳遞或作為回傳值。
Higher-order-function
一個function 如果可以做這2點,就可以稱為high-order-function高階函式:
- 當作一個function裡的參數來傳遞。
- 當作一個function的回傳值。
我們先來看當作 function參數的部分。下方程式碼的這個fuction就傳遞了2個參數。第1個是字串,第2個是一個function。
如下圖,在 function要描述一個傳遞的參數,使用參數名稱:參數型別
的寫法。所以紅色的部分是參數的名稱,而藍色是參數的型別。
第2個參數(String) -> Unit
,就是用來描述這個傳入 function 的特徵:包含參數及回傳值,這種用來表達 function 參數特徵的寫法就叫Function type。
所以(String) ->Unit
指的是這個Function Type 傳入一個String參數、沒有回傳值。
我先新增一個hello
function。呼叫highOrderFun("Evan", ::hello)
傳入hello這個function。
可以直接傳入::hello是因為hello這個function的特徵跟highOrderFun裡傳遞的第2個參數Function type是一樣的,如下圖所示。
這樣我們就做到了 function的參數是一個 function。
Lambda expression
lambda 是用來表達一個匿名函式,也就是沒有名稱的函式。
上面的範例,其實我們不需要宣告一個叫做 hello 的 function,可以使用匿名函式的方式直接傳入一個 function,所以不需要 hello
這個 function了,我我們把::hello
改成用 lambda 的方式。
如下圖,原本在hello function裡做的事,就直接在highOrderFun裡傳入一個匿名函式。
接著可以按下option+enter,Move lambda argument out of parentheses。
就會把{name -> println("Hello $name"}
移到()之後
而 lambda expression 裡如果只有一個參數,就可以再省略為使用it
來表示傳進來的參數。
接著再來看另一個例子,這個 function type 為傳入2兩個參數,且有回傳值如下。在 lambda expression要回傳值,不需要加return
,只要再最後一行寫上回傳值是什麼,如下圖的 "Result:${x + y}"
就是回傳值。
所以你也可以這樣寫,最後一行的result
就代表回傳值。
那像這樣的 lambda expression,我們也可以把他存到變數。也就是我們在一開始提到的First-class其中一個需符合的:fuction可以當變數來使用。
下圖你可以看到其實跟一般變數的宣告方式是沒什麼不一樣的。
接著,我們知道Kotlin有型別推斷(Type inference)的功能,所以你能再簡化成這樣:
最後我們來看一個在 Kotlin 常用的 Lambda expression 寫法。下方程式碼是我們常用的List裡 filter
功能。這裡的{ it > 1}
就是一個Lambda expression,指的是我要將這個List篩選出>1的
如果進去看filter
這個 function 原始碼,可以看到filter 的參數傳入了一個function:(predicate: (T) -> Boolean)
所以你可以寫成這樣,在 filter 傳入一個function
最後簡化的結果就是我們常用的寫法numbers.filter{ it > 1 }
總結一下Function type的寫法
//有1個參數,無回傳值
(Int) -> Unit//有2個參數,有回傳值
(Int, Int) -> String//無參數,無回傳值
() -> Unit