Kotlin Lambda和高阶函数

这篇具有很好参考价值的文章主要介绍了Kotlin Lambda和高阶函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Lambda和高阶函数

本文链接:

lambda

1、lambda的由来

  1. 单词"lambda"源于希腊字母λ(小写lambda)
  2. "Lambda"一词最早起源于数学中的λ演算(lambda calculus),它是一种函数定义和函数应用的形式系统,由逻辑学家阿隆佐·邱奇(Alonzo Church)在20世纪30年代发明。
  3. 邱奇使用λ作为演算中的一个操作符,用于表示匿名函数。他选择使用希腊字母λ的原因是因为它在字母表中的位置不太常见,这样可以避免与其他符号混淆。

2、函数的声明

    // 函数的声明
    val method01:()->Unit
    val method02:(Int, Int)->Unit
    val method03:(String, Double)->Any // 相当于Object
    val method04:(String, Double, Float)->Boolean

3、kotlin中Any和Java的Object有什么区别吗?

  1. Any是所有非空类型的超类型,类似于Java中的Object。Object不能持有null。
  2. Any?是所有类型的超类型,包括可空类型。
    Any?可以持有null值

4、函数如何调用/函数的实现(lambda)?invoke是什么?

// 函数变量通过invoke()调用
// ()是运算符重载
// 函数的实现
val method01:()->Unit
method01 = { println("我实现了method01") }
method01() // 调用函数:操作符重载
method01.invoke() // 调用函数:真实方法


// 方法三的实现
val method03:(String, Double)->Any // 相当于Object
method03 = {name, number ->
    println("$name $number")
    name + number
}
println(method03("wch", 1234567.89))

5、函数的实现(传入函数)

val method04:(String, Double, Float)->Boolean
    = fun(name:String, number:Double, age:Float):Boolean = (name+number+age).isEmpty()
method04("wch", 376.23, 1234.5f)

6、单一参数的lambda默认持有it ===> 函数式接口 ===> SAM

    val method05:(Int)->Unit = {
        print("$it")
    }

7、下划线可以拒收 ===> 拒收

    val method06:(Int, Int)->Unit = { _, number->
            println("$number")
    }

8、作用是什么?

  1. 节省空间
  2. 接口版本变化,有的参数没用了

9、想要允许参数为null,需要用可空类型如String?

val method07:(String?,String)->Unit = {
        sex, name -> println("$sex,$name")
    }

method07(null, "wch")

10、Lambda不可以使用泛型作为参数类型
11、Lambda参数不可以给默认值 ===> 默认参数
12、Lambda Any->Any

    // 传入什么,打印什么,还可以返回任何东西
    val method18:(Any)->Any={
        println("$it")
        it // 还可以返回自己
    }

13、Lambda配合扩展方法 ===> 扩展方法 ===> 官网写的Funciton,但是接收receiver

    val method19: String.()->Unit = {
        // this = String本身 == 调用者本身
        println("你是$this")
    }
    "WCH".method19()

14、为什么method19可以成为String的扩展方法?

  1. 代码val method19: String.()->Unit = { ... }表示定义了一个接收者类型为String的扩展函数类型。
  2. String.()->Unit表示该函数类型接收一个String作为接收者,并返回Unit类型(即没有返回值)。
  3. 进一步理解:==> 匿名扩展函数
val method18: ()->Unit; // 类型是 函数
val method19: String.()->Unit // 类型是 String的扩展函数
val method20: (String)->Unit // 类型是 函数,该函数的参数是String

15、进一步融合this和it,区分扩展函数 和 参数的区别

val method20: Int.(Int) -> String = {"两数相加的结果:${this+it}"}
println(1.method20(10))

println(method20(1, 10)) // 1, 可以自动插为第一个参数

函数的形式:

fun Int.method21(n:Int):String{
    return "两数相加的结果:${this+n}"
}
println(2.method21(22))
// println(method21(2, 22)) // 不可以这样写了

输出(返回类型)

1、Lambda的返回类型:函数

    /**============================
     * 函数
     *============================*/
    // 默认Unit
    fun t01(){ println() }
    // 默认Unit
    fun t02(){4652342.5f}
    // 默认Unit
    fun t03(){"Hello!"}
    // String:显式指明返回值
    fun t04():String{return "feather"} // return 还不支持自动推断类型

2、函数返回函数

    /**==============================
     * 函数返回函数
     *=============================*/
    // ()->Unit
    fun s01() = {}
    fun s02() = { println("Haha") }
    s02()() // 输出

    // Boolean
    fun s03() = run{ true }// 返回的是代码块的最后一行
    s03()
    // ()->String
    fun s04():()->String = {"Hello"}
    println(s04()) // Function0<java.lang.String>
    println(s04()())

3、Java中Lambda是假的

深入探究

4、Lambda深入探究

    // k01()返回的类型是: (Int)->Unit
    fun k01() = {n:Int -> println(n) }
    k01()(123)

    // lambda使用,第一种用的多
    val methodx2 = {str:String -> str.length}
    val methodx2s:(String)->Int = {it.length}

5、Kotlin的Lambda如何和Java兼容?源码机制

  1. kotlin编译器实现(很强大) -> JVM字节码
  2. package kotlin.jvm.functions中定义了Function系列
  3. 最多Funciton22,高版本编译器可以处理>22个参数的情况,低版本会出错
// val methodx2 = {str:String -> str.length}
Function1 methodx2 = (Function1)null.INSTANCE;
// (String)->Unit
val method3:Function1<String, Unit> = { println(it) }

6、Lambda考题

    //(Int,Int) -> (Int,Int) ->String
    val funX10 = fun(n1:Int,n2:Int):(Int,Int)->String={n1,n2 -> "两个数相加:${n1 + n2}"}
    println(funX10(10, 10)(20, 20))

    // 迷惑点,最外层的n1和n2和内层的n1 n2没关系
// 函数的函数的函数的函数
    val k01: (String) -> (Boolean) -> (Int) -> (Float) -> Double =
        { it ->
            { it ->
                { it ->
                    { it ->
                        123.456
                    }
                }
            }
        }
    println(k01("AAA")(true)(45)(67.89f))

7、下面的study02()返回的类型是什么?

fun study02() = {lambda:(Int, Int) -> String, studyInfo: String ->
    lambda(1, 99)
}
// 答案:((Int, Int) -> String, String) -> Unit 

// 使用:
study02()({n1, n2-> "$n1 + $n2 = ${n1 + n2}" }, "wch")

8、下面study04()返回的类型是什么?

fun study04() = {str:String, num:Int, lambda1:(String)->Unit, lambda2:(Int)->Boolean->
    lambda1(str)
    lambda2(num)
}
// 答案:(String,Int,(String)->Unit,(Int)->Unit)->Boolean

// 使用:
println(study04()("wch", 123, { println("$it lambda1") }, { it > 99}))

泛型

9、下面返回的类型是什么?

fun <T1, T2, R1, R2> study05() = {str:T1, num:T2, lambda1:(T1)->R1, lambda2:(T2)->R2 ->
    lambda1(str)
    lambda2(num)
}
// (T1, T2, (T1)->R1, (T2)->R2) -> R2

// 使用:
study05<String, Int, Boolean, Float>()("wch", 22, {it.isEmpty()}, {it.toFloat()})

10、下面的study06不是lambda,是函数。他们的类型是什么?

fun study05() = {Str:String, num: Int, lambda:(Int)->Boolean ->
    lambda(num)
}
// (String, Int, (Int)->Boolean)->Boolean

fun study06() = fun(Str:String, num: Int, lambda:(Int)->Boolean):Boolean{
    return lambda(num)
}
// (String, Int, (Int)->Boolean)->Boolean
  1. Lambda表达式,最后一行作为返回值
  2. 函数,最后一行不能作为返回值
  3. 必须显式return
  4. 必须显式指定

函数有隐式的Unit类型返回值

inline原理探究

1、Lambda为什么要内联?

  1. 不使用内联,会构造出Function0对象,作为参数传入
  2. 代码内联,减少方法调用开销,不再需要创建Function0对象 ===> 内存抖动
fun main() {
    show{
        println("Hello Kotlin!")
    }
}
fun show(lambda:()->Unit){
    lambda()
}
// 不使用内联生成代码:
show((Function0)null.INSTANCE);
public static final void show(@NotNull Function0 lambda) {
    Intrinsics.checkNotNullParameter(lambda, "lambda");
    lambda.invoke();
}
// 使用内联:
int $i$f$show = false;
int var1 = false;
String var2 = "Hello Kotlin!";
System.out.println(var2);

高阶函数

===> Compose内部实现,学习

1、高阶函数是什么?高阶函数 = lambda + 函数

fun a() {}
val a1 = {} // 函数引用,接收,匿名函数
val a2 = a1 // 函数引用
val a3 = ::a // 将函数变成函数引用

2、高阶函数就是函数的函数,函数中有lambda

// Lambda开胃菜
    // 返回String
    fun show01(number:Int, lambda:(Int)->String) = lambda.invoke(number)
    // 调用函数
    var r01 = show01(99){
        it.toString()
    }

    // return Int
    fun show02(n1:Int,n2:Int,n3:Int, lambda: (Int,Int,Int)->Int) = lambda(n1, n2, n3)
    show02(10, 20, 30){
        i, i2, i3 ->
            i + i2 + i3
    }

3、高阶函数例子

// 第一版,高阶函数应用
fun main() {
    loginEngine("wch", "123456")
}

private fun loginEngine(name:String, pwd:String){
    loginServer(name, pwd){
        code, msg->
            print("错误码$code 错误信息$msg")
    }
}

private fun loginServer(name:String, pwd:String, lambda:(Int, String)->Unit){
    if(name.isEmpty() || pwd.isEmpty()){
        lambda(-1, "Empty")
        return
    }
    lambda(1, "Success")
}
// 第二版

4、高阶函数

// (一)给泛型增加匿名扩展函数
fun<T> T.myRun01(block: T.(Float) -> Boolean) = block(123.45f)
// this = T本身 = 调用者本身 == Derry

// 使用
"Derry".myRun01 {
    isEmpty()
}

// (二)
fun<T> T.derry4(number:Double, mm: T.(Double) -> Unit){
    mm(number)
}
"Derry".derry4(123.456){
    // this = 调用者
    println(this)
}

// (三)
fun<T> T.myRunPlus(block: T.(T, T) -> Boolean) = block(this,this)

5、T.() -> Boolean s是什么意思?

  1. 对T扩展出匿名函数
  2. 匿名函数是 ()->Boolean
  3. 该匿名扩展函数只有这个高阶函数可以使用,其他地方用不出来

6、多个lambda调用

// (一)
show2(lambda1 = {}, lambda2 = {})
//(二)
show2({}, {})
// (三)
show2({println("Hello")}){
    println("World!")
}

7、源码使用高阶函数,利用函数引用

show(::lambdaImpl)

fun lambdaImpl(){
    println("HAHA")
}

// 函数引用场景
fun lambdaImpl(name:String):Unit{
    println(name)
}
var r1:Function1<String, Unit> = ::lambdaImpl
var r2:(String)->Unit = ::lambdaImpl
var r3:String.()->Unit = ::lambdaImpl // (String)等价于String.()

集合、泛型

1、Lambda+集合+泛型

class AndroidClickListener<T>{
    // 1. 集合的元素类型是Lambda,并且Lambda输入参数的类型是 T
    val actions = arrayListOf<(T)->Unit>()
    val actions2 = arrayListOf<(T?)->Unit>() // 可空
    
    // 2. 集合的元素类型为泛型
    val values = arrayListOf<T?>()

    // 3、设置监听
    fun addListener(value:T?, lambda:(T?)->Unit){
        values += value // 运算符重载
        actions2 += lambda
    }
    // 4、通知观察者
    fun notify(value:T?){
        val index = values.indexOf(value)
        actions2[index].invoke(value) // 执行方法
        actions2[index](value) // 执行方法二
    }
    // 5. 模拟点击事件,通知所有观察者
    fun touchListeners(){
        actions2.forEachIndexed{
            index, function ->  
                function(values[index])
        }
    }
}

// 使用,测试
    val click = AndroidClickListener<String>()
    click.addListener("HaHa"){
        println("接收到数据:$it")
    }
    click.addListener("WCH"){
        println("$it 在吃饭中...")
    }
    click.addListener("Feather"){
        println("百万博客主:$it")
    }
    click.touchListeners()


// 函数引用版本
    fun method(value:String?){
        println(value)
    }
    click.addListener("Hello", ::method)

2、如何用变量接收类型中包含泛型的函数?

fun<T> method(value: T?):Unit{
    println(value)
}
    // 不可以用泛型
//    val error:(T?)->Unit = ::method
    // Any来代表T?
    val m1:(Any)->Unit = ::method
    m1("Hello")
    // 具体类型也可以
    val m2:(Int)->Unit = ::method
    m2(123)

自己实现Kotlin内置函数

1、forEach

// 定义
inline fun<E> Iterable<E>.mForEach(lambda:(E)->Unit){
    for(item in this)lambda(item)
}

// 使用
listOf("AAA", "BBB", "CCC")
    .mForEach{
        println(it)
    }

2、let和run,为什么会有this,为什么会有it

  1. this,it
  2. T.()->R, this是对T的匿名扩展函数,拥有this
  3. (T)->R,it是参数类型,SAM单一抽象接口,函数式接口,it
public inline fun <T, R> T.run(block: T.() -> R): R {
    return block()
}
public inline fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}

3、thread

  1. 注意点: corssinline
// 自己实现thread,特定lambda不能inline
inline fun thread(start:Boolean = true,
                  name:String?=null,
                  crossinline runAction:()->Unit // 限制不能inline,会copy大量代码
):Thread{
    val thread = object:Thread(){
        override fun run() {
            super.run()
            runAction()
        }
    }
    if(start) thread.start() // 
    name?.let { thread.name = it } // kotlin形式
    return thread
}

扩展函数原理

1、扩展函数就是构造static final方法,将对象作为返回值

class MyKt {}
fun MyKt.show() = println(this)
public final class MyKt {}
// 构造出Kt类,添加扩展函数名一样的static final方法,将类的对象作为参数
public final class MyKtKt {
   public static final void show(@NotNull MyKt $this$show) {
      Intrinsics.checkNotNullParameter($this$show, "$this$show");
      System.out.println($this$show);
   }
}

2、思考:叫做扩展函数是否是因为没有receiver?

companion object 原理 ==> 静态内部类

1、为什么叫伴生对象?

  1. 生成静态内部类
  2. 生成静态成员变量(类变量)
  3. 通过伴生对象实例,调用方法和获取字段

2、使用处

class MyKt {
    companion object{
        fun show(){
            println(this)
        }
        val name = "wch"
    }
}

fun main() {
    MyKt.show()
    MyKt.name
}

3、反编译,生成源码

  1. 生成静态内部类,Companion,并且有show()方法和字段name
  2. 类中Companion实例,是static final变量
  3. 像Java一样调用类方法和获取类属性,本质通过Companion伴生对象,调用方法和get字段
public final class MyKt {
   private static final String name = "wch";
   public static final Companion Companion = new Companion((DefaultConstructorMarker)null);
   public static final class Companion {
      public final void show() {
         System.out.println(this);
      }

      public final String getName() {
         return MyKt.name;
      }

      private Companion() {
      }
      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

// 使用处
MyKt.Companion.show();
MyKt.Companion.getName();

函数式编程

Kotlin函数式编程文章来源地址https://www.toymoban.com/news/detail-655407.html

  1. 链式调用
  2. 非常丰富的函数库
  3. 模仿RxJava的响应式编程

到了这里,关于Kotlin Lambda和高阶函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Kotlin 操作集合的高阶函数

    Kotlin 提供了很多高阶函数用于对集合进行操作和转换。以下是一些常用的高阶函数: forEach{} :对集合中的每个元素执行指定的操作, 无返回 值。 map{} :对集合中的每个元素执行指定的操作, 返回 操作后的 集合 filter{} :对每一个元素进行筛选, 返回 满足条件的元素 集合

    2024年02月06日
    浏览(34)
  • Kotlin(十六) 高阶函数的简单应用

    高阶函数非常适用于简化各种API的调用,一些API的原有用法在使用高阶函数简化之后,不管是在易用性还是可读性方面,都可能会有很大的提升。 所以我们可以通过高阶函数来使一些API变得更简单更易读。在我们APP存储数据时,通常会用到SharedPreferences 这个API,那么我们现在

    2024年02月04日
    浏览(31)
  • 【Kotlin】探索回调机制:函数类型、高阶函数和接口

    当在 Kotlin 中开发应用程序时,经常会遇到需要使用回调机制的情况。回调是一种常见的编程模式,用于在异步操作完成后通知调用方,并处理相应的结果或事件。在 Kotlin 中,有几种不同的方法可以实现回调,包括使用函数类型、高阶函数和接口。每种方法都有其优点和适用

    2024年02月02日
    浏览(34)
  • Android开发:kotlin语言实现简易计算器

    输入两个数字,可选加减乘除操作符,并计算显示对应结果 随系统切换语言 可对结果进行四舍五入操作 界面布局:activity_main.xml文件代码 字符定义:string.xml文件代码 逻辑实现:MainActivity.kt 文件代码 方法一(偷懒): 复制文件到对应位置 方法二: 1. 绘制界面 2. 编写逻辑

    2023年04月08日
    浏览(29)
  • kotlin学习(二)泛型、函数、lambda、扩展、运算符重载

    Kotlin 中的类可以有类型参数,与 Java 类似: 创建这样类的实例只需要提供类型参数即可: 如果类型参数可以推断出来,例如从构造函数的参数或者从其他途径,就可以省略类型参数: String作为Object的子类,就可以直接将子类对象赋值给父类,这个操作即达到了 型变 。 但是

    2024年02月09日
    浏览(27)
  • Android 安卓开发语言kotlin与Java该如何选择

            如今在Android开发中,应用层开发语言主要是Java和Kotlin,Kotlin是后来加入的,主导的语言还是Java。kotlin的加入仿佛让会kotlin语言的开发者更屌一些,其实不然。         有人说kotlin的引入是解决开发者复杂的逻辑,并且对空指针控制的比较友好,但是我们在开

    2024年02月11日
    浏览(31)
  • 【Kotlin】函数式编程 ① ( 函数式编程简介 | 高阶函数 | 函数类别 | Transform 变换函数 | 过滤函数 | 合并函数 | map 变换函数 | flatMap 变换函数 )

    编程范式 指的是 使用某种编程语言的 编程套路 或 编程习惯 ; 使用 Java 等高级语言进行的编程 , 编程范式 一般都是 面向对象编程 ; 与 面向对象编程 同等级的另外一种 编程范式 是 函数式编程 , 函数式编程 不依赖于 指定的语言 , 所有的编程语言都可以使用 函数式编程范式

    2024年01月18日
    浏览(34)
  • kotlin基础--快速上手kotlin语言开发

    1.1 变量 var表示可变变量,val表示不可变变量,注意并不是常量。变量名写在前面,类型写在后面,编译器如果能推断出你的类型,那么类型是不用声明的 。 编译器自动推断类型。 空安全类型编译器报错 如果还是想给赋初始化值的话 注意:String和String?是两个完全不同的类

    2024年02月15日
    浏览(36)
  • 【第三阶段】kotlin语言的内置函数takeif

    执行结果

    2024年02月11日
    浏览(27)
  • Lambda 编程(Kotlin)一

    学习记录,以下为个人理解 知识点: Lambda的定义:允许你把代码块当作参数传递给函数 Lambda的语法约定: 如果lambda 表达式是函数调用的最后一个实参,它可以放到括号的外边 当lambda表达式时函数唯一的实参时,还可以去掉调用代码中的空括号对 简单来说,就是直接传递代

    2024年02月11日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包