文章说明
本文内容基于Kotlin官方文档总结翻译而成,旨在为自己学习Kotlin使用。文中的代码示例、技术概念和最佳实践均参考自Kotlin官方资源和相关技术文档,如需获取最新或更详细的信息,建议查阅官方文档。
1. Lambda表达式与高阶函数
Lambda表达式基础
Lambda表达式是一种简洁的方式来表示可以作为参数传递或从函数返回的函数。在Kotlin中,Lambda表达式总是用花括号括起来。
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
val sum = { x: Int, y: Int -> x + y }
|
Lambda表达式的基本组成部分:
- 参数声明位于花括号内,并可选择带有类型注解
- 函数体位于
->
符号后面
- 当Lambda表达式是函数的最后一个参数时,可以将其放在括号外(尾随Lambda)
- 单个参数的Lambda可以使用隐式名称
it
val product = items.fold(1) { acc, e -> acc * e }
val positiveNumbers = numbers.filter { it > 0 }
|
高阶函数
高阶函数是指将函数作为参数或返回函数的函数。Kotlin标准库中包含许多高阶函数。
fun <T, R> Collection<T>.fold( initial: R, combine: (acc: R, nextElement: T) -> R ): R { var accumulator: R = initial for (element: T in this) { accumulator = combine(accumulator, element) } return accumulator }
|
高阶函数的调用示例:
val sumOfItems = items.fold(0) { acc, item -> acc + item }
val product = items.fold(1, Int::times)
|
函数类型
Kotlin使用函数类型表示可以存储和传递的函数:
val onClick: () -> Unit = { println("Clicked!") }
val calculator: (Int, Int) -> Int = { x, y -> x + y }
val greeter: String.() -> Unit = { println("Hello, $this") }
|
函数类型的组成:
- 参数类型列表在括号内:
(Int, Int)
- 返回类型在箭头后面:
-> Int
- 可选的接收者类型在点前面:
String.() -> Unit
- 可以使用泛型参数:
<T> (T) -> T
内联函数
内联函数可以减少高阶函数的性能开销,通过在编译时将函数体直接插入到调用点:
inline fun executeWithLog(action: () -> Unit) { println("Before execution") action() println("After execution") }
executeWithLog { println("Action executed") }
|
内联函数的优势:
- 减少函数调用的开销
- 允许非局部返回(在Lambda中使用return退出外部函数)
- 支持具体化的类型参数(reified type parameters)
2. 函数式编程特性
函数类型与函数引用
Kotlin允许将函数作为值传递,通过使用函数引用(::
)操作符:
fun isOdd(x: Int) = x % 2 != 0 val numbers = listOf(1, 2, 3) val oddNumbers = numbers.filter(::isOdd)
val lengthsOfStrings = strings.map(String::length)
data class Person(val name: String) val createPerson = ::Person val person = createPerson("John")
|
闭包
Lambda表达式可以访问其外部作用域中的变量,形成闭包:
fun createCounter(): () -> Int { var count = 0 return { count++ count } }
val counter = createCounter() println(counter()) println(counter())
|
在闭包中,可以修改捕获的变量:
var sum = 0 numbers.filter { it > 0 }.forEach { sum += it }
|
柯里化
柯里化是将接受多个参数的函数转换为一系列接受单个参数的函数的技术:
fun add(x: Int, y: Int) = x + y
fun addCurried(x: Int) = { y: Int -> x + y }
val add5 = addCurried(5) val result = add5(3)
|
通过使用高阶函数实现柯里化:
fun <A, B, C> curry(f: (A, B) -> C): (A) -> (B) -> C { return { a -> { b -> f(a, b) } } }
val curriedAdd = curry { x: Int, y: Int -> x + y }
|
部分应用与函数组合
部分应用允许固定函数的部分参数,创建一个新函数:
fun multiply(a: Int, b: Int) = a * b
val double = { x: Int -> multiply(2, x) }
println(double(5))
|
函数组合允许将多个函数链接在一起,其中一个函数的输出作为下一个函数的输入:
fun square(x: Int) = x * x fun addOne(x: Int) = x + 1
val squareThenAddOne = { x: Int -> addOne(square(x)) }
println(squareThenAddOne(2))
|
3. 集合的函数式操作
转换操作
Kotlin集合API提供了丰富的函数式操作:
val numbers = listOf(1, 2, 3, 4, 5)
val squared = numbers.map { it * it }
val indexed = numbers.mapIndexed { index, value -> index to value }
val nestedLists = listOf(listOf(1, 2), listOf(3, 4)) val flattened = nestedLists.flatMap { it }
val evenOdd = numbers.groupBy { if (it % 2 == 0) "even" else "odd" }
|
过滤操作
过滤操作用于选择满足特定条件的元素:
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filter { it % 2 == 0 }
val odds = numbers.filterNot { it % 2 == 0 }
val firstThree = numbers.take(3)
val lastTwo = numbers.takeLast(2)
val skipFirst = numbers.drop(2)
|
聚合操作
聚合操作用于将集合元素合并为单个结果:
val numbers = listOf(1, 2, 3, 4, 5)
val sum = numbers.reduce { acc, next -> acc + next }
val sumWithInitial = numbers.fold(10) { acc, next -> acc + next }
val joined = numbers.joinToString(", ")
val evenCount = numbers.count { it % 2 == 0 }
val maxValue = numbers.maxOrNull()
|
序列操作
序列(Sequence)提供了惰性计算的集合操作,适用于大型集合:
val sequence = sequenceOf(1, 2, 3, 4, 5)
val fibonacci = sequence { var a = 0 var b = 1 while (true) { yield(b) val tmp = a + b a = b b = tmp } }
val result = fibonacci .take(10) .filter { it % 2 == 0 } .map { it * it } .toList()
|
序列与集合操作的区别:
- 集合操作是即时(eager)的,每步操作都会创建新的集合
- 序列操作是惰性(lazy)的,直到最终结果被请求时才会计算
- 序列适合处理大型集合或需要中途终止的操作
4. 作用域函数
Kotlin标准库提供了一组函数,用于在对象的上下文中执行代码块:
let
let
函数接收对象作为参数(it),并返回Lambda结果:
val length = str?.let { it.length }
val numbers = listOf("one", "two", "three") val modifiedFirst = numbers.first().let { firstItem -> println("First item: $firstItem") firstItem.uppercase() }
|
run
run
函数将对象作为接收者(this),并返回Lambda结果:
val result = service.run { port = 8080 query(prepareRequest()) }
val regex = run { val digits = "0-9" val letters = "A-Za-z" Regex("[$digits$letters]+") }
|
with
with
函数接收对象作为参数,并将其作为接收者(this)提供,返回Lambda结果:
val result = with(user) { name = "John" age = 25 "User updated: $name, $age" }
with(numbers) { println("Size: $size") println("First: ${first()}") println("Last: ${last()}") }
|
apply
apply
函数将对象作为接收者(this),并返回对象本身:
val user = User().apply { name = "John" age = 25 email = "john@example.com" }
val file = File("text.txt").apply { setReadable(true) setWritable(true) setExecutable(false) }
|
also
also
函数接收对象作为参数(it),并返回对象本身:
val numbers = mutableListOf(1, 2, 3) .also { println("Before adding: $it") } .add(4)
val user = createUser().also { log.info("Created user: ${it.name}") }
|
作用域函数的选择指南:
- 处理非空值和变量引入:
let
- 对象配置:
apply
- 对象配置和计算结果:
run
- 附加效果:
also
- 对象的多个操作:
with
参考链接