Kotlin 笔记 3.10:高阶函数和 Lambda 表达式

高阶函数

高阶函数是指将函数作为参数或者返回值的函数。

函数类型

在 Kotlin 中,每个函数都有特定的类型,函数类型由 函数的形参列表 + -> + 返回值类型 组成,例如:

fun getName(id:String):String{
}

上面这个 getName 函数的函数类型就是 (String) -> String

如果是没有返回值的函数:

fun setName(name: String){
}

上面的函数的函数类型就是:(String)->Unit 或者也可以简写为 (String)

如果是无参的函数:

fun getName():String{
}

上面的函数的函数类型就是 ()->String

在 Kotlin 中,函数类型既可以作为变量,也可以作为形参还可以作为返回值类型来使用。

定义一个变量,其类型为函数类型:

var test : (String) ->String

这样一个变量定义完成之后,然后我们开始使用这个变量:

fun main() {
    var test: (String) -> String
    test = ::getName
    println(test("ccccc"))

    //下面就会报错,因为函数类型不同
//    test = ::getNameList
    //修改一下函数类型,就可以了
    var test1: () -> MutableList<String>
    test1 = ::getNameList
}

fun getName(id: String): String {
    when (id) {
        "aaaaa" -> return "张三"
        "bbbbb" -> return "李四"
        else -> return "王五"
    }
}

fun getNameList(): MutableList<String> {
    return mutableListOf<String>("张三", "李四", "王五")
}

将函数类型作为形参

上面说过了,函数类型可以作为形参传入,我们可以将函数类型作为形参传入到方法中,又因为不同的方法可能形参相同,那么就可以在一个方法中去调用不同的方法了,一个简单的例子:

fun main() {

    var sum = mathOperation(1, 2, ::sum)
    println("加法: $sum")
    var sub = mathOperation(1, 2, ::sub)
    println("减法: $sub")
    var mult = mathOperation(1, 2, ::mult)
    println("乘法: $mult")
    var div = mathOperation(1, 2, ::div)
    println("除法: $div")

}

/**
 * compute 就是一个函数类型,作为参数,在方法体内可以直接调用相关方法
 */
fun mathOperation(a: Int, b: Int, compute: (Int, Int) -> Int): Int {
    return compute(a, b)
}

fun sum(a: Int, b: Int): Int {
    return a + b
}

fun sub(a: Int, b: Int): Int {
    return if (a >= b) {
        a - b
    } else {
        b - a
    }
}

fun mult(a: Int, b: Int): Int {
    return a * b
}

fun div(a: Int, b: Int): Int {
    return if (a >= b) {
        a - b
    } else {
        b - a
    }
}
输出结果:
加法: 3
减法: 1
乘法: 2
除法: 1

将参数类型作为返回值

将参数类型作为返回值,然后返回值可以作为方法直接使用:

fun main() {

    var matchFunc = getMathFunc("cube")
    println(matchFunc(5))
    matchFunc = getMathFunc("square")
    println(matchFunc(5))
    matchFunc = getMathFunc("other")
    println(matchFunc(5))

}

fun getMathFunc(type: String): (Int) -> Int {
    //定义一个计算平法的局部函数
    fun square(n: Int): Int {
        return n * n
    }

    //定义一个计算立方的局部函数
    fun cube(n: Int): Int {
        return n * n * n
    }

    //定义一个计算阶乘的局部函数
    fun factorial(n: Int): Int {
        var result = 1
        for (index in 2..n) {
            result *= index
        }
        return result
    }

    return when (type) {
        "square" -> ::square
        "cube" -> ::cube
        else -> ::factorial
    }
}
//示例代码来自《疯狂 Kotlin 讲义》
//执行结果:
125
25
120

Lambda 表达式

Lambda 本质是一种匿名函数,作为表达式,它的运行结果可以作为表达式、形参和函数返回值。

Lambda 表达式的格式大致为:

{
    参数->Lambda体
}

在上一个例子中,when 表达式的每个分支都又另外调去了一个局部方法,每个方法(方法体中)都有不同的计算形式,既然函数可以作为返回值,那么上面那个例子就可以修改为

fun main() {

    var matchFunc = getMathFunc("cube")
    println(matchFunc(5))
    matchFunc = getMathFunc("square")
    println(matchFunc(5))
    matchFunc = getMathFunc("other")
    println(matchFunc(5))

}

fun getMathFunc(type: String): (Int) -> Int {
    return when (type) {
        "square" -> return { n: Int -> n * n }
        "cube" -> return { n: Int -> n * n * n }
        else -> return { n: Int ->
            var result = 1
            for (index in 2..n) {
                result *= index
            }
            result
        }
    }
}
//执行结果是一样的

其实不难发现,上面那个例子,实际上就是将整个函数作为返回值,《疯狂 Kotlin 讲义》中总结了 Lambda 的几个特点:

  • Lambda 表达式总是被大括号括着
  • 定义 Lambda 表达式作为一个方法,不需要 fun 关键字,也无须指定方法名
  • 如果有形参列表,要放在 -> 前面,参数类型可以省略
  • 函数体放在 -> 后面
  • 函数的最后一个表达式默认为 Lambda 的返回值,且无须 return 关键字