【2023】Kotlin教程
文章目录
第二篇 面向对象与函数式编程
第13章 函数式编程基石——高阶函数和Lambda表达式
函数式编程思想虽然与面向对象一样立即悠久,但是支持函数式编程的计算机语言不过是近几年的事情。这些语言有Swift、Python、Java 8和C++ 11等,作为新生的语言Kotlin也支持函数式编程。
13.3 Lambda表达式
Lambda表达式是一种匿名函数,可以作为表达式、函数参数和函数返回值使用,Lambda表达式的运算结果是一个函数。
13.3.3 Lambda表达式简化写法
Kotlin提供了多种Lambda表达式简化写法,下面介绍其中几种。
【1】参数类型推导简化
类型推导是Kotlin的强项,Kotling编译器可以根据上下文环境推导出参数类型和返回值类型。以下代码是标准形式的Lambda表达式:
{
a:Int, b:Int -> a + b}
Kotlin能推导出参数a和b是Int类型,当然返回值也是Int类型。简化形式如下:
{
a, b -> a + b}
使用这种简化方式修改后的calculate函数代码如下:
private fun calculate(opr: Char): (Int, Int) -> Int = when (opr) {
'+' -> {
a, b -> a + b }
'-' -> {
a, b -> a - b }
'*' -> {
a, b -> a * b }
else -> {
a, b -> a / b }
}
fun main() {
val f1 = calculate('+')
val f2 = calculate('-')
val f3 = calculate('*')
val f4 = calculate('/')
println(f1(10, 5))
println(f2(10, 5))
println(f3(10, 5))
println(f4(10, 5))
}
【2】使用尾随Lambda表达式
Lambda表达式可以作为函数的参数传递,如果Lambda表达式很长,就会影响程序的可读性。如果一个函数的最后一个参数是Lambda表达式,那么这个Lambda表达式可以放在函数括号之后。
示例代码如下:
fun calculatePrint1(funN: (Int, Int) -> Int) {
// 使用funN 参数
println("${
funN(10, 5)}")
}
// 打印计算结果函数
fun calculatePrint(n1: Int, n2: Int, opr: Char, funN: (Int, Int) -> Int) {
println("$n1 $opr $n2 = ${
funN(n1, n2)}")
}
fun main() {
calculatePrint(10, 5, '+', {
a: Int, b: Int -> a + b }) // 标准形式
calculatePrint(10, 5, '-') {
a, b -> a - b } // 尾随Lambad表达式形式
calculatePrint1({
a, b -> a + b }) // 标准形式
calculatePrint1() {
a, b -> a + b } // 尾随Lambda表达式形式
calculatePrint1 {
a, b -> a + b } // 尾随Lambda表达式, 如果没有参数可以省略()
}
【注意】尾随Lambda表达式容易被误认为是函数声明
【3】省略参数声明
如果Lambda表达式的参数只有一个,并且能够根据上下文环境推导出它的数据类型,那么这个参数声明可以省略,在Lambda体中使用隐式参数it替代Lambda表达式的参数。示例代码如下:
fun reverseAndPrint(str: String, funN: (String) -> String) {
val result = funN(str)
println(result)
}
fun main() {
reverseAndPrint("hello", {
s -> s.reversed() }) // 标准形式
reverseAndPrint("hello", {
it.reversed() }) // 省略参数, 使用隐式参数it
val result1 = {
a: Int -> println(a) } // 不能省略参数声明
val result2: (Int) -> Unit = {
println(it) } // 可以省略函数声明
result1(20)
result2(30)
}
反转并打印字符串高阶函数revreseAndPrint,它的第二个参数是一个函数类型。
注意 Lambda体中it隐式变量是由Kotlin编译器生成的,它的使用有两个前提:
- 一是Lambda表达式只有一个参数
- 二是根据上下文能够推导出参数类型。
比较代码val result1 = { a: Int -> println(a) } // 不能省略参数声明 val result2: (Int) -> Unit = { println(it) } // 可以省略函数声明
会发现,由于result1被未指定数据类型,编译器不能推导出来Lambda表达式的参数类型,所以不能使用it。而result2被指定了数据类型(Int) -> Unit,编译器能推导出Lambda:表达式的参数类型,所以可以使用it。