kotlin:函数式参数

在 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

掌握它,能让你写出更声明式、更易读的代码。

相关推荐
Pniubi6 小时前
HashMap的扩容和树化边界
java·开发语言
Mikko76 小时前
用 Java 复刻了高中时在塞班上玩的「熔岩矿车」:纯 Swing、零依赖、没有一张图片,一个 jar 双击就能玩
java·游戏开发·swing
知了学历孙老师6 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
Java爱好狂.6 小时前
Java初学者如何一周速通SpringBoot!
java·spring boot·后端·spring·高并发·架构师·java面试
秋饼7 小时前
LLM API密钥动态轮换实战:Spring Vault + Spring AI + 多Provider路由
java·ai·技术分享·后端开发
撩得Android一次心动8 小时前
Jetpack Compose 知识点整理2【个人用】
android·笔记·学习·kotlin·compose
福兮说9 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
罗西的思考9 小时前
【Agentic RL】Dressage Staleness 控制深度分析
人工智能·算法·机器学习
quaer9 小时前
弗洛伊德算法--判圈法寻找环的入口O(n) O(1)
数据结构·算法
紧跟先前的步伐10 小时前
Go AI Agent 实战 03|Token、上下文窗口与模型调用成本
java·人工智能·golang