详解Lambda表达式和高阶函数

一.Lambda表达式

1.定义

Lambda就是一小段可以作为参数传递的代码。

正常情况下,我们向某个函数传参时只能传入变量,而借助lambda却可以允许传入一小段代码(这一小段代码究竟是多小也没做要求,只要别太长就好,否则会影响代码的可读性),这就是lambda的定义,也是特别之处。

2.lambda表达式的语法结构

{参数名1:参数类型,参数名2:参数类型->函数体}

参数列表的结尾使用一个**->**符号,表示参数列表的结束以及函数体的开始。
函数体中可以编写任意行代码(不建议太长),并且最后一行代码会自动作为Lambda表达式的返回值。

3.用法示例1.0

val list = listOf("Apple","Banana","Orange");
val lambda = {
    
    fruit: String -> fruit.length}
val maxLengthFruit = list.maxBy(lambda)

这种比较啰嗦,可以简化的地方有很多
首先,我们不需要定义一个lambda变量,而是可以直接将lambda表达式传入maxBy函数当中
所以

3.用法示例2.0

val list = listOf("Apple","Banana","Orange");
val maxLengthFruit = list.maxBy({
    
    fruit: String -> fruit.length})

Kotlin规定,当lambda参数是函数的最后一个参数时,可以将lambda表达式移到函数括号的外面
所以

3.用法示例3.0

val list = listOf("Apple","Banana","Orange");
val maxLengthFruit = list.maxBy(){
    
    fruit: String -> fruit.length}

接下来,如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略
所以

3.用法示例4.0

val list = listOf("Apple","Banana","Orange");
val maxLengthFruit = list.maxBy{
    
    fruit: String -> fruit.length}

因为kotlin拥有出色的类型推导机制,所以Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型
所以

3.用法示例5.0

val list = listOf("Apple","Banana","Orange");
val maxLengthFruit = list.maxBy{
    
    fruit -> fruit.length}

最后,当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名(如果想要表示的清楚一些,也可以声明参数名),而是可以使用it关键字来代替
所以

3.用法示例6.0

val list = listOf("Apple","Banana","Orange");
val maxLengthFruit = list.maxBy{
    
    it.length}

二.高阶函数

1.引

像maxBy这种接收Lambda参数的函数就可以称为具有函数式编程风格的API,而如果你想要定义自己的函数式API,那就得借助高阶函数来实现了

2.高阶函数定义

如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数。

kotlin中除了有整型布尔类型等,还添加了函数类型

3.函数类型的定义格式

(String,Int) -> Unit

①**->左边的部分就是用来声明该函数接收什么参数的,多个参数之间用逗号隔开,如果不接收任何参数,写一对空括号就可以了。
->**右边的部分用于声明该函数的返回值是什么类型,如果没有返回值就使用Unit,它大致相当于Java中的void

4.高阶函数简单使用

fun example(func: (String,Int) -> Unit){
    
    
    func("hello",123);
}

5.详细说一下高阶函数的用途

高阶函数允许让函数类型的参数来决定函数的执行逻辑
即使是同一个高阶函数,只要传入不同的函数类型参数,那么它的执行逻辑和最终的返回结果就可能是完全不同的。
比如

fun num1AndNum2(num1: Int,num2: Int,operation:(Int,Int) -> Int): Int{
    
    
    val result = operation(num1,num2)
    return result
}

fun plus(num1: Int,num2: Int): Int{
    
    
    return num1 + num2
}

fun minus(num1: Int,num2: Int): Int{
    
    
    return num1 - num2
}

调用就可以

val result1 = num1AndNum2(100,80,::plus)
val result2 = num1AndNum2(100,80,::minus)

这样就会发现result1和result2是不同的,因为传入的函数参数不同。

6.高阶函数与Lambda表达式结合(重点)

上面的代码虽然能正常工作,但是如果每次调用任何高阶函数的时候都还得先定义一个与其函数类型参数相匹配的函数,那这样未免有点太复杂了,所以Kotlin还支持其他多种方式来调用高阶函数,比如Lambda表达式、匿名函数、成员引用等。其中Lambda表达式是最常见也是最普遍的高阶函数调用方式。

所以函数定义还是这样

fun num1AndNum2(num1: Int,num2: Int,operation:(Int,Int) -> Int): Int{
    
    
    val result = operation(num1,num2)
    return result
}

,但是调用可以改为

val result1 = num1AndNum2(100,80){
    
    num1,num2 ->
    num1 + num2
}
val result2 = num1AndNum2(100,80){
    
    num1,num2 ->
    num1 - num2
}

同时,你会发现Lambda表达式同样可以完整地表达一个函数的参数声明和返回值声明(因为Lambda表达式中的最后一行代码会自动作为返回值),但是写法更加精简。

6.高阶函数与Lambda表达式结合2.0

fun StringBuilder.build(block: StringBuilder.() -> Unit): StringBuilder{
    
    
    block()
    return this
}

这里我们给StringBuilder类定义了一个build扩展函数,这个扩展函数接收一个函数类型参数,并且返回值类型也是StringBuilder
①区别:它在函数类型的前面加上了一个StringBuilder.的语法结构,其实这才是定义高阶函数完整的语法规则,在函数类型的前面加上ClassName.,就表示这个函数类型是定义在哪个类当中的。
②将函数类型定义到StringBuilder类当中的好处:当我们调用build函数时传入的Lambda表达式将会自动拥有StringBuilder的上下文,同时这也是apply函数的实现方式。
现在我们就可以使用自己创建的build函数来简化StringBuilder构建字符串的方式了

val list = listOf("Apple","Banana","Orange")
val result = StringBuilder().build {
    
     
    append("Start eating fruits\n")
    for(fruit in list){
    
    
        append(fruit).append("\n")
    }
    append("Ate all fruits")
}

可以看到build函数的用法和apply基本上是一样的,只不过我们编写的build函数目前只能作用在StringBuilder类上面,而apply函数是可以作用在所有类上面的。

猜你喜欢

转载自blog.csdn.net/afdafvdaa/article/details/108965849