Kotlin 函数式编程:从 A 到 Z
函数式编程(FP)是一种将计算视为数学函数求值,并避免状态改变和可变数据的编程范式。Kotlin 作为一种多范式语言,提供了强大的工具来应用函数式方法,同时无需放弃熟悉的面向对象编程。在本文中,我们将解析 Kotlin 中函数式编程的核心概念:从纯函数和不可变性,到组合和单子等高级技术。
1. 函数式方法基础:纯函数与不可变性
函数式编程的基础建立在两个原则上:函数的纯度和数据的不可变性。
- 纯函数——其结果仅取决于传入的参数,并且没有副作用(不修改外部变量、不输出到控制台、不访问数据库)。
- 不可变性——意味着数据在创建后不能被修改。不是修改现有对象,而是创建其带有所需更改的新副本。
Kotlin 中纯函数和不纯函数的示例:
// 不纯函数:有副作用(输出到控制台)fun impureSum(a: Int, b: Int): Int { println("和:${a + b}") // 副作用 return a + b}
// 纯函数:仅计算fun pureSum(a: Int, b: Int): Int = a + b
// 不可变性:使用 val 而不是 vardata class User(val name: String, val age: Int) // val 使字段不可变fun main() { val user = User("Alice", 30) // user.age = 31 // 编译错误! val olderUser = user.copy(age = 31) // 创建新副本}使用 val 和带有 copy() 的 data class 是在 Kotlin 中保持不可变性的标准方式。
2. 高阶函数与 Lambda 表达式
Kotlin 支持将函数作为一等公民。这意味着函数可以作为参数传递、从其他函数返回并存储在变量中。接受或返回其他函数的函数称为高阶函数。
Lambda 表达式是创建匿名函数的紧凑方式。语法:{ 参数 -> 函数体 }。
// 高阶函数:接受一个 (Int, Int) -> Int 类型的函数fun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int { return operation(a, b)}
fun main() { // Lambda 表达式 val sum: (Int, Int) -> Int = { x, y -> x + y } val multiply: (Int, Int) -> Int = { x, y -> x * y }
println(operateOnNumbers(5, 3, sum)) // 8 println(operateOnNumbers(5, 3, multiply)) // 15
// 即时使用 Lambda println(operateOnNumbers(10, 2, { a, b -> a - b })) // 8
// 如果 Lambda 是最后一个参数,可以将其放在括号外(尾随 Lambda) println(operateOnNumbers(10, 2) { a, b -> a / b }) // 5}Kotlin 标准库广泛使用高阶函数:用于集合的 map、filter、reduce。
val numbers = listOf(1, 2, 3, 4, 5)val evenSquares = numbers .filter { it % 2 == 0 } // {2, 4} .map { it * it } // {4, 16}println(evenSquares) // [4, 16]3. 函数组合与柯里化
组合是将两个或多个函数合并以创建新函数的过程。Kotlin 没有像 Haskell 那样的内置组合运算符,但可以手动实现或使用扩展函数轻松实现。
// 两个函数的组合infix fun ((B) -> C).compose(f: (A) -> B): (A) -> C = { a -> this(f(a)) }
fun main() { val toInt: (String) -> Int = { it.toInt() } val square: (Int) -> Int = { it * it }
val squ