在 Kotlin 中,函数式编程的核心特性之一就是将函数作为"一等公民",这意味着函数可以像其他数据类型(如 String、Int)一样,被当作参数传递、赋值给变量,或作为返回值。
这通常被称为 高阶函数。
1. 基本概念:高阶函数
高阶函数是指将函数作为参数或返回值的函数。
// 一个接受函数作为参数的高阶函数
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y) // 调用传入的函数
}
// 使用:传递一个 Lambda 表达式(函数字面值)
val sum = calculate(10, 5) { a, b -> a + b } // 结果是 15
val product = calculate(10, 5) { a, b -> a * b } // 结果是 50
2. 函数类型
函数式参数的语法是 (参数类型) -> 返回类型。
// 定义一个函数类型变量
val greet: (String) -> Unit = { name -> println("Hello, $name!") }
// 作为参数类型
fun executeAction(action: () -> Unit) {
action()
}
3. 传递函数式参数的几种方式
方式一:Lambda 表达式(最常用)
listOf(1, 2, 3).filter { it > 1 } // `it > 1` 是一个 Lambda
方式二:函数引用(::)
如果已经有一个命名函数,可以直接引用它。
fun isEven(number: Int): Boolean = number % 2 == 0
val numbers = listOf(1, 2, 3, 4)
val evens = numbers.filter(::isEven) // 引用现有函数
方式三:匿名函数
与 Lambda 类似,但可以更明确地指定返回类型。
numbers.filter(fun(num): Boolean {
return num % 2 == 0
})
4. 有用的语法糖
-
最后一个 Lambda 可移出括号:如果函数的最后一个参数是函数类型,Lambda 可以放在圆括号外。
// 这两种写法等价 calculate(10, 5, { a, b -> a + b }) calculate(10, 5) { a, b -> a + b } // 更推荐,更清晰 -
唯一参数是 Lambda 时可省略括号:如果函数只有一个参数且是函数类型,调用时可以直接写 Lambda。
run { println("执行!") } // `run` 的函数签名是 `run(block: () -> R)` -
隐式参数
it:当 Lambda 只有一个参数时,可以省略声明,用it指代。listOf("A", "B").forEach { println(it) } // 而不是 { str -> println(str) }
5. 带接收者的函数类型
这是 Kotlin 中 DSL(领域特定语言)和扩展函数式编程的基础。例如 apply、with和 run标准库函数。
// 类型:`String.() -> Unit` 表示在 `String` 的上下文中执行的函数
fun buildString(action: StringBuilder.() -> Unit): String {
val sb = StringBuilder()
sb.action() // 在 sb 的上下文中调用传入的 Lambda
return sb.toString()
}
val result = buildString {
append("Hello, ") // 这里的 `this` 是 StringBuilder 实例
append("World!")
}
// result 为 "Hello, World!"
总结
Kotlin 的函数式参数是其现代、简洁、表达力强的关键。它广泛应用于:
-
集合操作 (
filter、map、forEach) -
作用域函数 (
let、apply、also、run、with) -
回调处理和异步编程
-
构建类型安全的 DSL
掌握它,能让你写出更声明式、更易读的代码。