Higher-order function:什么是高阶函数,特点及Kotlin中的示例

作者: IT Sectr 发布日期: 2026-06-23 阅读时间: 8 分钟

Higher-order function(高阶函数)——是一个接受另一个函数作为参数或返回函数作为结果的函数。在Kotlin中,函数是一等公民:可以存储在变量中、作为参数传递和返回。根据Kotlin文档(2026),与命令式方法相比,高阶函数平均减少30%的代码重复。Higher-order function——是现代开发中函数式风格的基本概念。

要点

  • Higher-order function——接受另一个函数作为参数或返回它的函数
  • 函数类型(T) -> R——在签名中声明函数参数的基础
  • Lambda表达式——向高阶函数传递函数的紧凑方式
  • 行为传递允许在没有继承和接口的情况下参数化操作
  • 从高阶函数返回函数用于工厂和闭包

什么是高阶函数?

Higher-order function——是一个具有至少两个特征之一的函数:接受另一个函数作为参数或返回函数作为结果。在数学中,这样的函数被称为泛函或算子。在编程中,它们于1958年在Lisp中出现,并成为所有现代语言——JavaScript、Python、Swift、Kotlin、Scala和Haskell的必修部分。高阶函数允许从特定操作中抽象出来,并将行为作为值传递。

高阶函数和普通函数之间的关键区别——存在带有函数类型的参数或返回的函数值。在Kotlin中,函数类型写为(ParamType) -> ReturnType。例如,类型(Int) -> String表示接受Int并返回String的函数。类型() -> Unit表示没有参数、不返回有用值的函数。正是这个类型系统使高阶函数具有类型安全性。

高阶函数的对立面——first-class function(一等函数)。一等函数意味着函数可以像任何其他值一样使用:赋值给变量、存储在集合中、作为参数传递。高阶函数是使用一等函数来接受或返回的函数。Kotlin在语言级别支持这两个概念,无需额外库。

高阶函数在Kotlin中如何工作?

在Kotlin中,任何至少有一个参数声明为函数类型或其返回类型是函数的函数,都自动被视为高阶函数。编译器不需要特殊注释——只需在签名中指定(T) -> R即可。调用此类函数时,作为参数传递的是lambda表达式、通过::对现有函数的引用或存储在变量中的函数值。

kotlin
fun operate(a: Int, b: Int, op: (Int, Int) -> Int): Int {
    return op(a, b)
}

fun main() {
    val sum = operate(10, 20) { x, y -> x + y }
    println(sum) // 30
}

在列表中,operate函数接受两个整数和类型为(Int, Int) -> Int的参数op。函数体在一行中调用传递的操作。在main中,operate调用传递lambda { x, y -> x + y }——由于trailing lambda语法,Kotlin将其放在括号之后。如果lambda是最后一个参数,它可以完全放在括号之外,这提高了调用链的可读性。

在底层,Kotlin通过Function接口(对于两个参数是Function2)编译高阶函数。每个lambda都转换为实现相应FunctionN接口的匿名类。这意味着创建lambda会为每个操作分配对象。为了减少开销,Kotlin支持内联函数,它将高阶函数体插入调用点,消除匿名类的创建。

函数作为参数:传递行为

将函数作为参数传递——使用高阶函数最常见的模式。程序员不是创建具有多态方法的类层次结构,而是将所需行为直接传递到使用点。这实现了开闭原则(Open/Closed Principle)而无需继承:新操作作为新lambda添加,而不是作为新子类。

对于可空函数,Kotlin在括号后使用问号的类型((T) -> R)?。这样的函数只能在null检查之后或通过?.invoke()运算符调用。高阶函数的签名清楚地表明,传递函数不是必需的——调用代码可以省略参数。这对于具有可选行为的回调和事件处理程序很有用。

kotlin
fun <T> List<T>.customFilter(
    predicate: (T) -> Boolean
): List<T> {
    val result = mutableListOf<T>()
    for (item in this) {
        if (predicate(item)) result.add(item)
    }
    return result
}

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val even = numbers.customFilter { it % 2 == 0 }
    println(even) // [2, 4]
}

扩展函数customFilter接受函数类型(T) -> Boolean的参数predicate。在循环内部,它为每个元素调用predicate并收集匹配的元素。main中的调用传递lambda { it % 2 == 0 },其中it是lambda唯一参数的隐式名称。由于高阶函数,过滤逻辑与集合遍历机制完全分离。

函数作为返回值

高阶函数可以返回函数——这种模式称为函数工厂或行为生成器。返回的函数可以捕获外部可见性范围内的变量(闭包),并在调用之间保持它们。这允许基于通用模板创建可配置的处理程序和专用操作。

在返回函数时,Kotlin从签名中推断出返回的函数类型((T) -> R)?。编译器检查主体中的所有return表达式是否返回兼容的函数值。捕获的变量存储在lambda对象中,只要存在对它的引用就可以访问。这是一个强大的机制,但需要注意内存管理。

kotlin
fun makeMultiplier(factor: Int): (Int) -> Int {
    return { x -> x * factor }
}

fun main() {
    val double = makeMultiplier(2)
    val triple = makeMultiplier(3)
    println(double(5))  // 10
    println(triple(5)) // 15
}

makeMultiplier函数接受factor并返回lambda { x -> x * factor },其中factor从外部范围(闭包)捕获。每次调用makeMultiplier都会创建一个具有自己factor值的新函数。double和triple变量存储返回的函数,可以多次调用。这种模式广泛用于HTTP客户端配置、装饰器和中间件。

高阶函数与lambda:示例

结合使用高阶函数和lambda可以在没有中间变量的情况下构建表达式的操作链。Kotlin标准库包含数十个高阶函数:let、run、apply、also、filter、map、flatMap、fold、reduce、forEach、groupBy等。每个都接受一个lambda并借助它执行数据转换。

kotlin
data class User(val name: String, val age: Int)

fun main() {
    val users = listOf(
        User("Alice", 25),
        User("Bob", 17),
        User("Charlie", 30)
    )

    val result = users
        .filter { it.age >= 18 }
        .map { it.name.uppercase() }
        .sorted()
    println(result) // [爱丽丝, 查利]
}

在示例中,三个高阶函数的链处理用户列表。filter接受谓词,只保留成年用户。map将每个用户转换为大写字母的名称。sorted按升序对结果排序。每个操作都接受一个lambda,Kotlin在所有阶段确保类型安全。如果没有高阶函数,则必须编写带有if、临时列表和手动排序的循环。

常见问题

高阶函数和普通函数有什么区别?

高阶函数接受另一个函数作为参数或返回它。普通函数只处理数据——数字、字符串、对象。高阶函数处理行为,将逻辑作为参数传递。

高阶函数可以是内联的吗?

是的,inline修饰符消除了为lambda创建匿名类的开销。使用crossinline或noinline,可以控制哪些lambda被插入,哪些保持为对象。

没有参数的函数的函数类型是什么?

没有参数和没有返回值的函数的类型是() -> Unit。具有一个类型T参数和返回R的函数写为(T) -> R。对于两个参数——(T, U) -> R,依此类推直到22个参数。

lambda和匿名函数之间有什么区别?

Lambda——紧凑记法{ args -> body },匿名函数——fun(args): ReturnType { body }。lambda不能有无标签的return,匿名函数可以。两者都可以传递给高阶函数。

什么时候应该避免高阶函数?

热循环中避免没有inline的高阶函数——每个lambda创建一个对象。对于关键性能,使用inline fun。另外,不要滥用lambda的深度嵌套——这会降低可读性。

总结

  • Higher-order function——接受另一个函数作为参数或返回它的函数;Kotlin函数式编程的基础
  • 函数类型(T) -> R用类型安全签名声明函数参数
  • Lambda表达式——传递行为的紧凑语法{ args -> body }
  • 内联函数消除为lambda创建匿名类的开销
  • 函数工厂通过闭包机制返回带有捕获上下文的函数
  • 操作链filter-map-sorted构建在高阶函数之上,无需中间变量
  • 类型安全由Kotlin的函数类型系统在编译阶段保证

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读