Kotlin学习笔记——(八)高阶函数案例

注:编码工具为IntelliJ

目录

Kotlin的lambda表达式实现原理

高阶函数

函数作为函数参数

函数作为函数的返回值

高阶函数使用案例

回调

高阶函数配合扩展函数使用

函数作为最后一个参数的调用方式

模仿监听


Kotlin的lambda表达式实现原理

        Kotlin内部定义了一系列FunctionX接口,在Function.kt文件中,开发者定义的lambda表达式(匿名函数),Kotlin底层会通过实现FunctionX接口的方式实现。

package step_eight

fun main() {
    var method = { println("lambda表达式/匿名函数")}
    var method2 = {string: String -> println(string)}
    var method3 : (Int, Int) -> String = {a, b -> (a + b).toString()}
}

反编译为Java代码后:

public final class LambdaTruthKt {
   public static final void main() {
      Function0 method = (Function0)null.INSTANCE;
      Function1 method2 = (Function1)null.INSTANCE;
      Function2 method3 = (Function2)null.INSTANCE;
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

上面的Function0、Function1、Function2都是定义在Function.kt文件中的接口,Function.kt的部分内容:

/*
 * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

// Auto-generated file. DO NOT EDIT!

package kotlin.jvm.functions

/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
    /** Invokes the function. */
    public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2): R
}
/** A function that takes 3 arguments. */
public interface Function3<in P1, in P2, in P3, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2, p3: P3): R
}

高阶函数

函数作为函数参数

        可以将lambda表达式(匿名函数)或者满足作为参数的函数的声明类型的普通函数的函数引用作为实际参数传给函数。

        lambda表达式(匿名函数)作为函数的最后一个参数传递时,可以放在()的外面。

package step_eight

private fun show(str: String, action: (String) -> Unit) = action(str)

private fun calc(num1: Int, num2: Int, action: (Int, Int) -> Int) = action(num1, num2)

fun main() {
    // lambda表达式(匿名函数)作为实际参数
    show("Higher Order Function", action = { println(it)})
    // 普通函数的函数引用作为实际参数
    show("Higher Order Function", ::println)

    val num1 = 30
    val num2 = 90
    println("$num1 + $num2 = ${calc(num1, num2, { i, j -> i + j })}")
    println("$num1 - $num2 = ${calc(num1, num2, { i, j -> i - j })}")
    println("$num1 * $num2 = ${calc(num1, num2, { i, j -> i * j })}")
    println("$num1 / $num2 = ${calc(num1, num2, { i, j -> i / j })}")
}

输出:

Higher Order Function
Higher Order Function
30 + 90 = 120
30 - 90 = -60
30 * 90 = 2700
30 / 90 = 0

函数作为函数的返回值

        函数执行的结果是一个函数,还能执行一次。暂时想不到有什么用途。

package step_eight

private fun op() = { msg: String -> println(msg) }

fun main() {
    // op的执行结果是一个函数,还能执行一次,所以有两组()
    op()("Higher Order Function")

    // 复杂情况
    var method = fun(a: Int, b: Int): (Int, Int) -> String =
        { i, j -> "$i + $j = ${i + j} \n a = $a \n b = $b" }
    println(method(10, 18)(100, 200))

    var method2 : (String) -> (String) -> (Boolean) -> (Int) ->(String) -> Int =
    {
        println("第一层 it = $it");
        {
            println("第二层 it = $it");
            {
                println("第三层 it = $it");
                {
                    println("第四层 it = $it");
                    {
                        println("第五层 it = $it");
                        it.length
                    }
                }
            }
        }
    }
    println(method2("Higher")("Order")(true)(10000)("Function"))
}

输出:

Higher Order Function
100 + 200 = 300 
 a = 10 
 b = 18
第一层 it = Higher
第二层 it = Order
第三层 it = true
第四层 it = 10000
第五层 it = Function
8

高阶函数使用案例

回调

package step_eight

private fun login(name: String, pwd: String, response: (String, String) -> Unit){
    if("root" == name && "123456" == pwd){
        response("登录成功", "200")
    }else{
        response("用户名或密码错误", "400")
    }
}

fun main() {
    login("admin", "admin"){
        msg, code ->
        println("msg = $msg, code = $code")
    }
}

输出:

msg = 用户名或密码错误, code = 400

高阶函数配合扩展函数使用

package step_eight

private fun <T, R> T.work(action: T.()-> R): R = action()

fun main() {
    println("kouniqiwa".work {
        println(this)
        "hi"
    })

    println(123.work { this.times(10) })

    println("I LOVE YOU BABY".work { lowercase() })
}

输出:

kouniqiwa
hi
1230
i love you baby

函数作为最后一个参数的调用方式

package step_eight

private fun show(msg: String, func: (String) -> Unit) = func(msg)

fun main() {
    show("time machine", func = { println(it) })
    show("Stone", { println(it) })
    show("Happy") { println(it) }
}

输出:

time machine
Stone
Happy

模仿监听

package step_eight

class ListenerOp<T>{
    val actions = arrayListOf<(T) -> Unit>()
    val values = arrayListOf<T>()

    fun action(){
        if(actions.isEmpty()){
            println("没有监听器")
        }else{
            actions.forEachIndexed { index, function ->
                function(values[index])
            }
        }
    }

    fun setListener(value: T, action: (T) -> Unit){
        values += value
        actions += action
    }
}

fun main() {
    val listener = ListenerOp<String>()
    listener.action()
    listener.setListener("Hi"){ println(it) }
    listener.setListener("What Do I Call You"){ println(it) }
    listener.setListener("Destiny"){ println(it) }

    fun <T> funcRef(t: T){
        println(t)
    }
    listener.setListener("century ago", ::funcRef)

    fun console(str: String) = println(str)
    listener.setListener("测试", ::console)
    val r = ::console
    listener.setListener("测试函数引用", r)

    listener.action()
}

输出:

没有监听器
Hi
What Do I Call You
Destiny
century ago
测试
测试函数引用

上一篇:python学习scipy使用, 学习笔记


下一篇:Android中使用CameraX实现拍照和录像(Kotlin实现)