3-1-2 高阶函数-与 Lambda 结合运用

14 阅读2分钟

Kotlin 高级函数与 Lambda 结合运用

Kotlin 中高级函数与 Lambda 表达式的结合使用是函数式编程的核心特性,可以写出简洁、表达力强的代码。让我详细介绍这些概念及其实际应用。

1. 基础 Lambda 表达式

// 基本 Lambda 语法
val sum = { x: Int, y: Int -> x + y }

// 调用 Lambda
println(sum(5, 3)) // 输出: 8

// 作为函数参数
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach { println(it) }

// 单参数时,it 关键字
val doubled = numbers.map { it * 2 }

2. 函数类型与高阶函数

// 函数类型声明
typealias Operation = (Int, Int) -> Int

// 高阶函数:接收函数作为参数
fun calculate(a: Int, b: Int, operation: Operation): Int {
    return operation(a, b)
}

// 高阶函数:返回函数
fun getMultiplier(factor: Int): (Int) -> Int {
    return { number -> number * factor }
}

// 使用示例
val addition: Operation = { x, y -> x + y }
val result = calculate(10, 5, addition) // 15

val double = getMultiplier(2)
println(double(5)) // 10

3. 常用高阶函数实践

集合操作

data class Person(val name: String, val age: Int)

val people = listOf(
    Person("Alice", 29),
    Person("Bob", 31),
    Person("Charlie", 25),
    Person("Diana", 28)
)

// filter 与 map 结合
val namesOfAdults = people
    .filter { it.age >= 18 }
    .map { it.name }
    .sorted()

// groupBy
val groupedByAge = people.groupBy { it.age / 10 * 10 }
// 结果: {20=[...], 30=[...]}

// fold 与 reduce
val totalAge = people.fold(0) { acc, person -> acc + person.age }
val oldest = people.reduce { p1, p2 -> if (p1.age > p2.age) p1 else p2 }

// flatMap
val allHobbies = people.flatMap { person -> 
    getHobbies(person) // 假设返回 List<String>
}

作用域函数

data class User(var name: String, var age: Int, var email: String?)

// let - 安全调用与转换
val userEmailLength = user?.let { 
    it.email?.length ?: 0
}

// apply - 对象配置
val user = User("", 0, null).apply {
    name = "Alice"
    age = 30
    email = "alice@example.com"
}

// run - 执行代码块并返回结果
val userInfo = user.run {
    "Name: $name, Age: $age"
}

// with - 非扩展函数版本
with(user) {
    println("User: $name")
    // 多个操作
}

// also - 附加操作
val processedUser = user.also {
    println("Processing user: ${it.name}")
    // 可以修改 it
}.copy(age = user.age + 1)

4. 自定义高阶函数

带接收者的 Lambda (DSL 构建)

// 定义 HTML DSL
class Html {
    private val children = mutableListOf<Any>()
    
    fun body(init: Body.() -> Unit) {
        val body = Body().apply(init)
        children.add(body)
    }
    
    override fun toString() = children.joinToString("\n")
}

class Body {
    private val elements = mutableListOf<String>()
    
    fun h1(text: String) {
        elements.add("<h1>$text</h1>")
    }
    
    fun p(text: String) {
        elements.add("<p>$text</p>")
    }
    
    override fun toString() = elements.joinToString("\n")
}

// 使用 DSL
val html = Html().apply {
    body {
        h1("Welcome")
        p("This is a paragraph.")
    }
}

日志记录高阶函数

fun <T> withLogging(operationName: String, block: () -> T): T {
    println("Starting $operationName")
    val startTime = System.currentTimeMillis()
    
    val result = try {
        block()
    } catch (e: Exception) {
        println("Error in $operationName: ${e.message}")
        throw e
    }
    
    val endTime = System.currentTimeMillis()
    println("Finished $operationName in ${endTime - startTime}ms")
    
    return result
}

// 使用
val data = withLogging("data processing") {
    // 复杂的数据处理
    processLargeDataset()
}

5. Lambda 与 Receiver 的进阶用法

// 创建配置构建器
class DatabaseConfig {
    var url: String = ""
    var username: String = ""
    var password: String = ""
    var poolSize: Int = 10
    
    fun build(): String = "jdbc:$url?user=$username&password=$password&poolSize=$poolSize"
}

fun database(block: DatabaseConfig.() -> Unit): String {
    val config = DatabaseConfig().apply(block)
    return config.build()
}

// 使用构建器
val connectionString = database {
    url = "mysql://localhost:3306/mydb"
    username = "admin"
    password = "secret"
    poolSize = 20
}

6. 函数组合与管道

// 函数组合
infix fun <A, B, C> ((B) -> C).compose(g: (A) -> B): (A) -> C = { x -> this(g(x)) }
infix fun <A, B, C> ((A) -> B).andThen(f: (B) -> C): (A) -> C = { x -> f(this(x)) }

// 使用函数组合
val add5 = { x: Int -> x + 5 }
val multiplyBy2 = { x: Int -> x * 2 }
val square = { x: Int -> x * x }

val composed = add5 andThen multiplyBy2 andThen square
println(composed(3)) // ((3+5)*2)^2 = 256

// 管道操作
fun <T, R> T.pipe(vararg functions: (T) -> R): R {
    var result: Any = this
    for (function in functions) {
        result = function(result as T)
    }
    return result as R
}

val result = 10.pipe(
    { it * 2 },
    { it + 5 },
    { it.toString() }
) // "25"

7. 实际应用示例

验证器构建器

class Validator<T> {
    private val validations = mutableListOf<(T) -> Boolean>()
    
    fun addValidation(message: String, predicate: (T) -> Boolean) {
        validations.add(predicate)
    }
    
    fun validate(value: T): List<String> {
        return validations.mapNotNull { validation ->
            if (!validation(value)) "Validation failed" else null
        }
    }
}

fun <T> buildValidator(block: Validator<T>.() -> Unit): Validator<T> {
    return Validator<T>().apply(block)
}

// 使用
val userValidator = buildValidator<User> {
    addValidation("Name must not be empty") { it.name.isNotBlank() }
    addValidation("Age must be positive") { it.age > 0 }
    addValidation("Email must be valid") { it.email.contains("@") }
}

重试机制

suspend fun <T> withRetry(
    maxAttempts: Int = 3,
    initialDelay: Long = 100,
    maxDelay: Long = 1000,
    block: suspend () -> T
): T {
    var currentDelay = initialDelay
    repeat(maxAttempts - 1) { attempt ->
        try {
            return block()
        } catch (e: Exception) {
            println("Attempt ${attempt + 1} failed: ${e.message}")
            delay(currentDelay)
            currentDelay = (currentDelay * 2).coerceAtMost(maxDelay)
        }
    }
    return block() // 最后一次尝试
}

8. 性能注意事项

  1. 内联函数:使用 inline 关键字避免 Lambda 开销
inline fun <T> measureTime(block: () -> T): T {
    val start = System.currentTimeMillis()
    val result = block()
    val end = System.currentTimeMillis()
    println("Execution time: ${end - start}ms")
    return result
}
  1. 避免重复创建 Lambda:在循环外定义 Lambda
// 避免
repeat(1000) {
    list.filter { it > 5 }.forEach { println(it) }
}

// 推荐
val filterPredicate = { it: Int -> it > 5 }
val action = { it: Int -> println(it) }
repeat(1000) {
    list.filter(filterPredicate).forEach(action)
}

总结

Kotlin 的高级函数和 Lambda 表达式结合使用可以:

  1. 提高代码表达力:使代码更简洁、意图更明确
  2. 促进函数组合:通过函数组合构建复杂行为
  3. 支持 DSL 创建:构建领域特定语言
  4. 增强代码复用:通过高阶函数抽象通用模式
  5. 简化异步编程:配合协程使用

掌握这些技巧可以帮助你写出更优雅、可维护的 Kotlin 代码。