【2023】Kotlin教程
第二篇 面向对象与函数式编程
第13章 函数式编程基石——高阶函数和Lambda表达式
函数式编程思想虽然与面向对象一样立即悠久,但是支持函数式编程的计算机语言不过是近几年的事情。这些语言有Swift、Python、Java 8和C++ 11等,作为新生的语言Kotlin也支持函数式编程。
13.4 闭包与捕获变量
闭包(closure)是一种特殊的函数,它可以访问函数体之外的变量,这个变量和函数一同存在,即使已经离开了它的原始作用域也不例外。这种特殊函数一般是局部函数、匿名函数或Lambda表达式。
闭包可以访问函数体之外的变量,这个过程称为捕获变量。示例代码如下:
// 全局变量
var value = 10
fun main() {
// 局部变量
var localValue = 20
var result = {
a: Int ->
value++
localValue++
val c = a + value + localValue
println(c)
}
result(30) // 62
println("localValue = " + localValue) // 21
println("value = " + value) // 11
}
本例中的闭包是捕获value和localValue变量的Lambda表达式。在Lambda体中捕获变量value和localValue。
【给Java程序员的提示】Java中,Lambda表达式捕获局部变量时,局部变量只能是final的。在Lambda体中只能读取局部变量,不能修改局部变量。而Kotlin中没有这个限制,可以读取和修改局部变量。
【注意】闭包捕获变量后,这些变量被保存在一个特殊的容器中被存储起来。即便是声明这些变量的原始作用域已经不存在,闭包体中仍然可以访问这些变量。
下面是一个局部函数示例:
fun makeArray(): (Int) -> Int {
var ary = 0
// 局部函数捕获变量
fun add(element: Int): Int {
ary += element
return ary
}
return ::add
}
fun main() {
val f1 = makeArray()
println("---f1---")
println(f1(10))
println(f1(20))
println(f1(30))
}
ary 变量的作用域是makeArray 函数体,在局部函数add 函数体内,修改了变量ary 的值,并返回。
这样一来,当主函数中进行调用时,f1 是局部函数add 的一个变量,而且需要注意的是,f1 每次调用的时候,ary 的变量作用域已经不存在了,所以ary 变量可以被保持。
这个栗子也可以用匿名函数实现,代码如下:
fun makeArray(): (Int) -> Int {
var ary = 0
// 局部函数捕获变量
return fun(element: Int): Int {
ary += element
return ary
}
}
fun main() {
val f1 = makeArray()
println("---f1---")
println(f1(10))
println(f1(20))
println(f1(30))
}
makeArray函数返回一个Lambda表达式,。比较Lambda表达式与匿名函数和局部函数,会发现Lambda表达式代码最为简洁,最后实现的结果完全一样。