Kotlin 的High-order functions 與 Lambdas

Evan Chen
Evan Android Note
Published in
May 9, 2022

Kotlin 的 function是屬於一級函式(first-class function),意思是 function可以像變數一樣被使用,也能在一個high-order-function 中被當作參數來傳遞或作為回傳值。

Higher-order-function

一個function 如果可以做這2點,就可以稱為high-order-function高階函式:

  1. 當作一個function裡的參數來傳遞。
  2. 當作一個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

--

--