Lambda 與高階函數#

Lambda 是一種匿名函數,可以像值一樣被傳遞;高階函數(Higher-Order Function) 是接受函數作為參數、或回傳函數的函數。兩者是 Kotlin 函數式程式設計風格的核心。


1. Lambda 基本語法#

1
val 變數名稱: (參數型別) -> 回傳型別 = { 參數 -> 函數體 }

範例#

1
2
3
4
fun main() {
    val greet: (String) -> String = { name -> "Hello, $name!" }
    println(greet("Alice")) // 輸出:Hello, Alice!
}

it:單一參數的簡寫#

當 Lambda 只有一個參數時,可以省略參數宣告,直接使用 it 代替。

1
2
3
4
fun main() {
    val double: (Int) -> Int = { it * 2 }
    println(double(5)) // 輸出:10
}

2. 高階函數#

函數作為參數#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

fun main() {
    val sum = calculate(3, 4) { x, y -> x + y }
    val product = calculate(3, 4) { x, y -> x * y }

    println("加法:$sum")      // 輸出:加法:7
    println("乘法:$product")  // 輸出:乘法:12
}

函數作為回傳值#

1
2
3
4
5
6
7
8
9
fun makeMultiplier(factor: Int): (Int) -> Int {
    return { number -> number * factor }
}

fun main() {
    val triple = makeMultiplier(3)
    println(triple(5))  // 輸出:15
    println(triple(10)) // 輸出:30
}

3. 集合的高階函數#

這是 Lambda 最常見的應用場景。


map:轉換每個元素#

1
2
3
4
5
6
7
8
9
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val doubled = numbers.map { it * 2 }
    println(doubled) // 輸出:[2, 4, 6, 8, 10]

    val names = listOf("alice", "bob", "carol")
    val upper = names.map { it.uppercase() }
    println(upper) // 輸出:[ALICE, BOB, CAROL]
}

filter:篩選符合條件的元素#

1
2
3
4
5
6
7
8
9
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
    val evens = numbers.filter { it % 2 == 0 }
    println(evens) // 輸出:[2, 4, 6, 8]

    val words = listOf("apple", "banana", "avocado", "cherry")
    val aWords = words.filter { it.startsWith("a") }
    println(aWords) // 輸出:[apple, avocado]
}

reduce:將集合歸納為單一值#

1
2
3
4
5
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val sum = numbers.reduce { acc, n -> acc + n }
    println(sum) // 輸出:15
}

fold:與 reduce 類似,但可指定初始值#

1
2
3
4
5
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val sumFrom100 = numbers.fold(100) { acc, n -> acc + n }
    println(sumFrom100) // 輸出:115
}

forEach:遍歷每個元素#

1
2
3
4
5
6
7
8
fun main() {
    val fruits = listOf("Apple", "Banana", "Cherry")
    fruits.forEach { println(it) }
    // 輸出:
    // Apple
    // Banana
    // Cherry
}

any / all / none:條件判斷#

1
2
3
4
5
6
7
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)

    println(numbers.any { it > 4 })   // 輸出:true(有任何元素 > 4)
    println(numbers.all { it > 0 })   // 輸出:true(所有元素 > 0)
    println(numbers.none { it > 10 }) // 輸出:true(沒有元素 > 10)
}

鏈式呼叫#

多個高階函數可以串接,形成流暢的資料處理管線。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
data class Product(val name: String, val price: Int, val inStock: Boolean)

fun main() {
    val products = listOf(
        Product("筆記型電腦", 35000, true),
        Product("滑鼠", 800, true),
        Product("鍵盤", 1500, false),
        Product("螢幕", 12000, true)
    )

    val result = products
        .filter { it.inStock }          // 只取有庫存的
        .filter { it.price < 20000 }    // 價格低於 20000
        .map { it.name }                // 只取名稱
        .sorted()                       // 排序

    println(result) // 輸出:[滑鼠, 螢幕]
}

4. 尾隨 Lambda(Trailing Lambda)#

當函數的最後一個參數是 Lambda 時,可以將 Lambda 移到括號外面,讓程式碼更易讀。

1
2
3
4
5
// 一般寫法
numbers.filter({ it > 3 })

// 尾隨 Lambda 寫法
numbers.filter { it > 3 }

5. withapply:作用域函數#

Kotlin 提供了幾個以 Lambda 為基礎的作用域函數(Scope Functions),讓物件操作更簡潔。

with:對物件執行多個操作,回傳 Lambda 結果#

1
2
3
4
5
6
7
8
9
data class Person(var name: String, var age: Int)

fun main() {
    val person = Person("Alice", 30)
    val info = with(person) {
        "姓名:$name,年齡:$age"
    }
    println(info) // 輸出:姓名:Alice,年齡:30
}

apply:對物件進行設定,回傳物件本身#

1
2
3
4
5
6
7
8
9
data class Person(var name: String = "", var age: Int = 0)

fun main() {
    val person = Person().apply {
        name = "Bob"
        age = 25
    }
    println(person) // 輸出:Person(name=Bob, age=25)
}

Reference#

https://kotlinlang.org/docs/lambdas.html