Kotlin Lambda 與高階函式

Kotlin 是 函數式程式語言 (Functional Programming) 的擁護者。 這意味著函式是 一等公民 (First-class citizen):可以被存成變數、當作參數傳遞、也可以當作回傳值。

Lambda 表達式

Lambda 就是一個「沒有名字的函式」。 語法:{ 參數 -> 程式本體 }

val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2)) // 3

高階函式 (Higher-Order Functions)

接受函式當作參數,或是回傳一個函式的函式,就叫高階函式。 最常見的例子就是集合操作常用的 filter、map。

val numbers = listOf(1, 2, 3, 4, 5)

// 把 lambda 傳給 filter
val evens = numbers.filter { it % 2 == 0 }

唯一的參數 (it)

如果 Lambda 只有一個參數,可以省略參數宣告 x ->,直接用 it 代表那個參數。

// 完整寫法
numbers.map { x -> x * 2 }

// 簡寫 (推薦)
numbers.map { it * 2 }

尾隨 Lambda (Trailing Lambda)

如果函式的 最後一個參數 是函式,你可以把 Lambda 把移到括號外面。

// 定義 High-Order Function
fun logic(n: Int, operation: (Int) -> Int) {
    println(operation(n))
}

// 呼叫方式 1
logic(5, { it * it })

// 呼叫方式 2 (推薦:尾隨寫法)
logic(5) { 
    it * it 
}

你看,這是不是很像在寫一個語言本身的語法結構?Android 的 Jetpack Compose 就是大量使用這種寫法。

函式型別 (Function Type)

變數可以存函式,那變數的型別是什麼?格式為 (參數型別) -> 回傳型別

val onClick: () -> Unit = { println("Clicked") }
val sum: (Int, Int) -> Int = { a, b -> a + b }

Closure (閉包)

Kotlin 的 Lambda 可以存取並「修改」外部的變數(Java 的 Lambda 只能存取 final 變數)。

var sum = 0
numbers.filter { it > 0 }.forEach {
    sum += it // 直接修改外部變數
}
println(sum)