深入kotlin - lambda 表达式和高阶函数

Posted 颐和园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入kotlin - lambda 表达式和高阶函数相关的知识,希望对你有一定的参考价值。

函数式编程

函数不依赖于任何类存在(从源代码级别上,从字节码层级,它仍然会依赖于类存在)。典型的如顶层函数。

lambda 表达式

lambda 表达式和 java 相同,它由被“箭头”符号(->)分隔的两个部分组成。箭头左边是括号包裹的参数列表(如果只有一个参数,括号可以省略),箭头右边是返回值类型:

// 定义 lambda 表达式的类型
(a: Int, b: Int) -> Int
// 定义 lambda 表达式实例
 a,b -> a+b  // 花括号包裹,不能省略
// 利用 lambda 实例推断出 lambda 的类型
val add =  a:Int, b:Int -> a+b 
// 无参数,无返回值(或者返回 Unit)
val action =  println("hello") 
// 允许函数为空
val action: ((Int,Int) -> Int)? = null

lambda 表达式作为参数

fun substract(a:Int, b: Int) = println(a-b)
fun test(a: Int = 1, b: Int = 2, compute: (x:Int, y:Int)->Unit)  
	compute(a,b)

... ...
test(2,3,::substract) // 1
test(2,3,  a,b -> println(a-b)) // 2
test(2,3) a,b -> println(a-b) // 3
test  a,b -> println(a-b)  // 4

compute 参数是一个 lambda 表达式,接收两个参数,返回 Unit(即 void,无返回值)。

  1. 这里将一个 方法引用(java8)传递给 compute 参数。方法引用的形式为类名::方法名,这里 substract 是顶层对象,没有类名,所以类名省略。
  2. 直接传递 lambda 表达式。注意,a,b 参数列表不需要用括号包裹。
  3. 尾随闭包写法。
  4. 使用默认参数的写法,注意,包括方法参数的括号可以省略,同时,尾随闭包不需要指定参数名。

lambda 表达式的参数

fun test(x: Int, action:()-> Unit)



fun test2(x: Int, action:(Int)->Unit)


fun main()
	test(5) println("aaa") // 1
  test2(5) println("bbb") // 2

  1. test 的 action 参数是一个不带参数的lambda,所以调用时不用声明任何 lambda 的参数。
  2. Test2 的 action 参数是有参数的 lambda,但在调用时同样可以不声明任何 lambda 参数。这是 kotlin 的一种语言特性,如果方法的 lambda 表达式只有一个参数,那么在调用时可以忽略,如果你要使用到这个参数,可以用隐含参数(it 关键字) 来引用。
fun test3()
fun test4(x:Int)
fun test5(x:Int, action:(Int,Int)->Unit)
	action(1,2)

fun test6(x:Int, y:Int) println(x+y) 
fun main()
  test(5, ::test3)
  test2(5, ::test4)
  test5(5, ::test6) // 1
  
  test5(5) // 2
    println("a")
  

  1. 将 test 6 的函数引用传递给 test5 的第二个参数。这样 test5 的唯一一句: action(1,2) 就变成了 test6(1,2) ,结果打印出:3。
  2. 编译错误。因为 test5 的 action 需要两个参数,lambda 表达式的参数就不能省略了,必须声明。

高阶函数

接收一个函数作为参数或者将一个函数作为返回值的函数,被称作高阶函数。如果一个函数的最后一个参数是函数,那么可以用 lambda 尾随闭包形式。Kotlin 中,lambda 表达式就是函数。

fun calculate(a:Int, b:Int, operation: (Int, Int)->Int): Int // 1
  return operation(a,b) // 2

... ...
println(calculate(2,3)a,b -> a+b)
  1. calculate 函数的最后一个参数是一个函数(即 lambda 表达式),因此是一个高阶函数。
  2. 调用 lambda 表达式并返回调用结果。

再看一个例子:

fun String.filter(predicate: (Char,Int) -> Boolean): String  // 1
    val i = 0
    var result = ""

    for(c in this.toCharArray()) // 2
        if(predicate(c, i)) // 3
            result += c
        
    
    return result // 4


fun main(args: Array<String>) 
    var string = "1324q22ddd"

    string = string.filter()
        ch, index ->  ch.isDigit() // 5
    
    println(string) // 打印:132422

  1. 为 String 扩展一个 filter 函数,这个函数是一个高阶函数,以一个 lambda 为参数。这个 lambda 会接受 2 个参数: 一个字符和该字符在字符串中的索引,返回 Boolean 表示是否接受该字符。

  2. 遍历字符串中每个字符。

  3. 用这个字符及其索引调用 lambda 表达式,如果表达式返回 true,则在返回结果中包含该字符,否则过滤该字符。

  4. 遍历结束,返回过滤的结果(一个新的字符串)。

  5. 调用 filter,用一个 lambda 表达式作为参数,该 lambda 表达式会根据传入的字符进行判断,如果该字符是数字,返回 true,否则返回 false。注意,这里 lambda 表达式最后一个表达式的值,默认会作为 lambda 表达式的返回值,因此不用 return。如果要 return,则需要使用全限定的方式 return。

    return@filter ch.isDigit() // 用 @ 符号显式指定是返回到 filter 而非当前函数
    

以上是关于深入kotlin - lambda 表达式和高阶函数的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin-lambda表达式和高阶函数操作符

玩转Kotlin--彻底弄懂Lambda和高阶函数

Python: 高阶函数与lambda表达式

Java 8 vs. Scala: Lambda表达式

1.16 高阶函数

Java高阶进阶之Java函数式编程-Stream流-Lambda表达式