Kotlin Lambda和高阶函数

Lambda和高阶函数

本文链接:

文章目录

    • Lambda和高阶函数
  • lambda
    • 输出(返回类型)
    • 深入探究
      • 泛型
    • inline原理探究
  • 高阶函数
    • 集合、泛型
    • 自己实现Kotlin内置函数
  • 扩展函数原理
  • companion object 原理 ==> 静态内部类
  • 函数式编程

lambda

1、lambda的由来

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

2、函数的声明

    // 函数的声明val method01:()->Unitval method02:(Int, Int)->Unitval method03:(String, Double)->Any // 相当于Objectval 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的返回类型:函数

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

2、函数返回函数

    /**==============================* 函数返回函数*=============================*/// ()->Unitfun s01() = {}fun s02() = { println("Haha") }s02()() // 输出// Booleanfun s03() = run{ true }// 返回的是代码块的最后一行s03()// ()->Stringfun s04():()->String = {"Hello"}println(s04()) // Function0<java.lang.String>println(s04()())

3、Java中Lambda是假的

深入探究

4、Lambda深入探究

    // k01()返回的类型是: (Int)->Unitfun 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) ->Stringval 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)->Booleanfun 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开胃菜// 返回Stringfun show01(number:Int, lambda:(Int)->String) = lambda.invoke(number)// 调用函数var r01 = show01(99){it.toString()}// return Intfun 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输入参数的类型是 Tval 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 = ::methodm1("Hello")// 具体类型也可以val m2:(Int)->Unit = ::methodm2(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 methodpublic Companion(DefaultConstructorMarker $constructor_marker) {this();}}
}// 使用处
MyKt.Companion.show();
MyKt.Companion.getName();

函数式编程

Kotlin函数式编程

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/42167.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flink流批一体计算(13):PyFlink Tabel API之SQL DDL

1. TableEnvironment 创建 TableEnvironment from pyflink.table import Environmentsettings, TableEnvironment# create a streaming TableEnvironmentenv_settings Environmentsettings.in_streaming_mode()table_env TableEnvironment.create(env_settings)# or create…

嵌入式Linux开发实操(九):CAN接口开发

前言: CAN网络在汽车中的使用可以说相当广泛。而CAN网络需要的收发器最常用的就是NXP 的TJA1042: CAN网络:

605. 种花问题

链接 假设有一个很长的花坛&#xff0c;一部分地块种植了花&#xff0c;另一部分却没有。可是&#xff0c;花不能种植在相邻的地块上&#xff0c;它们会争夺水源&#xff0c;两者都会死去。给你一个整数数组 flowerbed 表示花坛&#xff0c;由若干 0 和 1 组成&#xff0c;其中…

8/16总结

WebSocket是双向通信协议&#xff0c;模拟Socket协议&#xff0c;可以双向发送或者接收信息 而Http是单向的 WebSocket是需要浏览器和服务器握手进行建立连接的 而http是浏览器发起向服务器的连接&#xff0c;服务器预先并不知道这个连接 WebSocket在建立握手时&#xff0c;数…

Python3内置函数大全

吐血整理 Python3内置函数大全 1.abs()函数2.all()函数3.any()函数4.ascii()函数5.bin()函数6.bool()函数7.bytes()函数8.challable()函数9.chr()函数10.classmethod()函数11.complex()函数12.complie()函数13.delattr()函数14.dict()函数15.dir()函数16.divmod()函数17.enumer…

注解@JsonInclude

注解JsonInclude 1. 注解由来 JsonInclude是一个用于Java类中字段或方法的注解&#xff0c;它来自于Jackson库。Jackson库是一个用于处理JSON数据的流行开源库&#xff0c;在Java对象和JSON之间进行序列化和反序列化时经常被使用。 2. 注解示例 下面是JsonInclude注解的一个…

【kubernetes】Pod控制器

目录 Pod控制器及其功用 pod控制器有多种类型 1、ReplicaSet ReplicaSet主要三个组件组成 2、Deployment 3、DaemonSet 4、StatefulSet 5、Job 6、Cronjob Pod与控制器之间的关系 1、Deployment 查看控制器配置 查看历史版本 2、SatefulSet 为什么要有headless&…

2023-08-18力扣每日一题

链接&#xff1a; 1388. 3n 块披萨 题意&#xff1a; 一个长度3n的环&#xff0c;选n次数字&#xff0c;每次选完以后相邻的数字会消失&#xff0c;求选取结果最大值 解&#xff1a; 这波是~~&#xff08;ctrl&#xff09;CV工程师了~~ 核心思想是选取n个不相邻的元素一定…

无涯教程-Perl - splice函数

描述 此函数从LENGTH元素的OFFSET元素中删除ARRAY元素,如果指定,则用LIST替换删除的元素。如果省略LENGTH,则从OFFSET开始删除所有内容。 语法 以下是此函数的简单语法- splice ARRAY, OFFSET, LENGTH, LISTsplice ARRAY, OFFSET, LENGTHsplice ARRAY, OFFSET返回值 该函数…

Vue 项目运行 npm install 时,卡在 sill idealTree buildDeps 没有反应

解决方法&#xff1a;切换到淘宝镜像。 以下是之前安装的 xmzs 包&#xff0c;用于控制切换淘宝镜像。 该截图是之前其他项目切换淘宝镜像的截图。 切换镜像后&#xff0c;顺利执行 npm install 。

生成国密密钥对

在线生成国密密钥对 生成的密钥对要妥善保管&#xff0c;丢失是无法找回的。

selinux

一、selinux的说明 二、selinux的工作原理 三、selinux的启动、关闭与查看 Enforcing和permissive都是临时的&#xff0c;重启还是依据配置文件中&#xff0c;禁用selinux&#xff0c;修改配置文件&#xff1a; 之后重启生效 四、selinux对linux服务的影响

SpringBoot 接口调用出现乱码解决 中文乱码

SpringBoot 接口调用出现乱码解决 package com.cxjg.mvc.util;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springfra…

相同数字的积木游戏

题目描述 题目描述 小华和小薇一起通过玩积木游戏学习数学。 他们有很多积木&#xff0c;每个积木块上都有一个数字&#xff0c;积木块上的数字可能相同。 小华随机拿一些积木挨着排成一排&#xff0c;请小薇找到这排积木中数字相同目所处位置最远的2块积木块&#xff0c;计算…

【JAVA】我们该如何规避代码中可能出现的错误?(一)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 文章目录 前言三种类型的异常异常处理JAVA内置异常类Exception 类的层次 前言 异常是程序中的一些错误&#xff0c;但并不是所有的错误都是异常&#xff0c;并且错误有时候是可以避免的&…

【BASH】回顾与知识点梳理(三十三)

【BASH】回顾与知识点梳理 三十三 三十三. 认识系统服务 (daemons)33.1 什么是 daemon 与服务 (service)早期 System V 的 init 管理行为中 daemon 的主要分类 (Optional)systemd 使用的 unit 分类systemd 的配置文件放置目录systemd 的 unit 类型分类说明 33.2 透过 systemctl…

Grounding dino + segment anything + stable diffusion 实现图片编辑

目录 总体介绍总体流程 模块介绍目标检测&#xff1a; grounding dino目标分割&#xff1a;Segment Anything Model (SAM)整体思路模型结构&#xff1a;数据引擎 图片绘制 集成样例 其他问题附录 总体介绍 总体流程 本方案用到了三个步骤&#xff0c;按顺序依次为&#xff1a…

Tomcat 部署优化

Tomcat Tomcat 开放源代码web应用服务器&#xff0c;是由java代码开发的 tomcat就是处理动态请求和基于java代码的页面开发 可以在html当中写入java代码&#xff0c;tomcat可以解析html页面当中的iava&#xff0c;执行动态请求 动态页面机制有问题&#xff1a;不对tomcat进行优…

vue 使用indexDB 简单完整逻辑

1 npm npm install idb 2 代码 <template><div><p>Data: {{ data }}</p><button click"fetchData">Fetch Data</button></div> </template><script> import { openDB } from idb;export default {data() {…

eqtl-GWAS和GWAS-GWAS

目前教程中有eqtl-GWAS和GWAS-GWAS两种模式&#xff0c;其他模式比较少见&#xff0c;还未进行开发 数据类型cc为分类变量即case/control&#xff0c;quant为连续变量&#xff0c;eqtl数据默认quant coloc.abf有两个比较需要注意的点&#xff0c;就是数据集中N是代表样本量&am…