Kotlin(1)-lambda表达式和高阶函数操作符,真的已经讲烂了-程序员宅基地

技术标签: 程序员  android  kotlin  开发语言  

官方高阶函数

Kotlin谷歌已经给我们封装了一些高阶函数。

  • run
  • with
  • apply
  • also
  • let
  • takeif 和 takeunless
  • repeat
  • lazy
run函数详解

代码如下(这里为了展示代码全貌,忽视androidStudio的代码优化提示):

class A {
val a = 1
val b = “b”
}
fun testRun() {
//run方法有两种用法,一个是不依赖对象,也就是作为全局函数
run {//我可以规定返回值的类型
println(“我是全局函数”)
“返回值”
}
val a = A()
//另一种则是 依赖对象
a.run<A,String> {//这里同样可以规定返回值的类型
println(this.a)
println(this.b)
“返回值”
}
}
fun main() {
testRun()
}

如上所示:

run函数分为两类

  • 不依赖对象的全局函数。

  • 依赖对象的"类似"扩展函数。

两者都可以规定返回值类型(精通泛型的话,这里应该不难理解,泛型下一节详解)。

阅读源码:

@kotlin.internal.InlineOnly
public inline fun run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}

run函数被重载,参数有所不同

  • 前者 参数类型为 ()->R ,返回值为 R ,函数体内执行block(),并且返回执行结果
  • 后者 参数类型为 T.()->R ,返回值为R , T.() 明显是依赖 T类的(貌似T的扩展函数),返回值依然是R,执行完之后返回结果。
  • 并且,可以发现 两者都是内联函数 inline (执行代码时不进行方法的压栈出栈,而是类似于直接在目标处执行代码段)

所以,前者不需要依赖对象,后者必须依赖对象(因为它是T类的"扩展函数")

使用场景

根据run方法的特性,无论是不是依赖对象,它都是封装了一段代码,而且还是inline的。所以:

  • 如果你不想把一段代码独立成方法,又不想让它们看上去这么凌乱,最重要的是告诉后来的开发者 这段代码是一个整体,不要随便给我在里面插代码,或者拆分。那就用run方法,把他们整合到一个作用域中。

run {
println(“这是一段代码逻辑很相近的代码段”)
println(“但是我不想把他独立成一个方法”)
println(“又担心别人会随便改”)
println(“所以用run方法把他们放在同一个作用域中”)
println(“小组中其他人看到这段,就知道不要把无关代码插进来”)
}

  • 更神奇的是,这个run函数是有返回值的,参数返回值可以利用起来:

fun testRun2(param1: String, param2: String, param3: String) {
//我想让这几个参数都不为空,如果检查是空,就不执行方法主体
val checkRes: Boolean = run {
when {
param1.isNullOrEmpty() -> {
false
}
param2.isNullOrEmpty() -> {
false
}
param3.isNullOrEmpty() -> {
false
}
else -> true
}
}

if (checkRes){
println(“参数检查完毕,现在可以继续接下来的操作了”)
}else{
println(“参数检查不通过,不执行主体代码”)
}
}
fun main() {
testRun2(“1”, “2”, “”)
}

main运行结果:

小结论

run方法在整合小段代码的功效上,还是很实用的

其他高阶函数

上面列举出来的这些系统高阶函数原理上都差不多,只是使用场景有区别,因此除了run之外,其他的不再详解,而只说明使用场景。

apply

和run只有一个区别,run是返回block()执行之后的返回值,而,apply 则是返回this,因此 apply必须依赖对象。而由于返回了this,因此可以连续apply调用。

fun testApply() {
val a = A()
a.apply {
println(“如果一个对象要对它进行多个阶段的处理”)
}.apply {
println(“那么多个阶段都挤在一起则容易混淆,”)
}.apply {
println(“此时可以用apply将每一个阶段分开摆放”)
}.apply {
println(“让程序代码更加优雅”)
}
}

fun main() {
testApply()
}

with

下面的代码应该都很眼熟,Glide图片加载框架的用法,with(context)然后链式调用

Glide.with(this).load(image).asGif().into(mImageView);

Kotlin中的with貌似把这一写法发扬光大了(只是类比,不用深究),场景如下:

class A {
val a = 1
val b = “b”

fun showA() {
println(“$a”)
}

fun showB() {
println(“$a $b”)
}
}

fun testWith() {
val a = A()
with(a) {
println(“作用域中可以直接引用创建出的a对象”)
this.a
this.b
this.showA()
this
}.showB()
}

fun main() {
testWith()
}

细节

  1. with(a){} 大括号内的作用域里面,可以直接使用 当前a对象的引用,可以this.xxx 也可以 a.xxx
  2. with(a){} 大括号作用域内的最后一行是 返回值,如果我返回this,那么with结束之后,我可以继续 调用a的方法
also

also和with一样,必须依赖对象,返回值为this。因此它也支持链式调用,它和apply的区别是:

apply的block,没有参数,但是 also 则将this作为了参数。这么做造成的差异是:

作用域 { } 内调用当前对象的方式不同。

class A {
val a = 1
val b = “b”

fun showA() {
println(“$a”)
}

fun showB() {
println(“$a $b”)
}
}
fun testApply() {
A().apply {
this.showA()
println(“=======”)
}.showB()
}

fun testAlso() {
A().also {
it.showA()
println(“=======”)
}.showB()
}

apply 必须用this.xxx, also则用 it.xxx.

let

类比到run:

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)
}

只有一个区别:run的block执行不需要参数,而let 的block执行时需要传入this。

造成差异为:

A().run {
println(“最后一行为返回值”)
this
}.showA()

A().let {
println(“最后一行为返回值”)
it
}.showA()

run{} 作用域中 只能通过this.xxx操作当前对象,let 则用 it.xxx

takeif 和 takeunless

这两个作用相反,并且他们必须依赖对象。看源码:

public inline fun T.takeIf(predicate: (T) -> Boolean): T? {
return if (predicate(this)) this else null
}
public inline fun T.takeUnless(predicate: (T) -> Boolean): T? {
return if (!predicate(this)) this else null
}

predicate 是 (T)->Boolean 类型的lambda表达式,表示断言判断,如果判断为true,则返回自身,否则返回空

class A {
val a = 0
val b = “b”

fun showA() {
println(“$a”)
}

fun showB() {
println(“$a $b”)
}
}

fun testTakeIfAndTakeUnless() {
println(“test takeIf”)
A().takeIf { it.a > 0 }?.showB()
println(“==========”)
println(“test takeUnless”)
A().takeUnless { it.a > 0 }?.showB()
}

fun main() {
testTakeIfAndTakeUnless()
}

执行结果:

test takeIf

test takeUnless
0 b

takeIf / takeUnless适用于将条件判断的代码包在一个作用域{}中,然后 用 ?.xxxx的安全调用符 来 执行对象操作。

repeat

repeat是 多次循环的傻瓜版写法。

fun testRepeat() {
repeat(10) {
print("$it ")
}
}

fun main() {
testRepeat()
}

执行结果:

0 1 2 3 4 5 6 7 8 9

lazy

lazy的作用是: 延迟初始化val定义的常量。

class B {
val i: Int by lazy {
println(“执行i初始化”)
20
}

init {
println(“构造函数执行”)
}
}

如果只是初始化B对象,却没有使用到变量i, 那么延迟初始化不会执行。

fun main() {
B()
}

执行结果:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

d开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

[外链图片转存中…(img-3pI5nxxr-1712776104807)]

[外链图片转存中…(img-nqFxiUyr-1712776104808)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/2401_84123232/article/details/137619464

智能推荐

号外号外 震惊 震惊,人工智能中,训练一下模型,然后生成模型,都能申请专利,看看这个识别面部动作的专利-程序员宅基地

文章浏览阅读116次。这种专利有意思吗 有意义吗 有创新吗?和别人都是右手写字,我申请左手写字的专利 ,,有什么区别

jmeter接口测试自动获取cookie_xing2516_新浪博客-程序员宅基地

文章浏览阅读514次。jmeter接口测试自动获取cookie有时候我们接口地址和方式都对,就是报错,查看接口文档,其实需要加上消息头cookie,添加完cookie,不需要配置获取什么的,只要加一个访问网站的首页地址(HTTP请求),他会自动获取到cookie值添加cookie管理器加完cookie管理器,登录里就获取到了cookie值Jmeter请求参数3种形..._jmeter request body获取cookie

python difflib 编辑距离_Python Edit_Distance包_程序模块 - PyPI - Python中文网-程序员宅基地

文章浏览阅读413次。编辑距离用于计算序列之间编辑距离和对齐的python模块。我需要一种方法来计算python中序列之间的编辑距离。我没有能够找到任何合适的库来实现这一点,所以我自己编写了一个。在那里似乎有许多可用于计算编辑的编辑距离库两个字符串之间的距离,但不是两个序列之间的距离。这完全是用python编写的。这种实现可能是在python中优化为更快。如果在C中实现。库API是根据difflib.sequencem..._edit distance python lib

antd upload组件 手动上传-程序员宅基地

文章浏览阅读3.8k次,点赞2次,收藏15次。antd 的upload组件是点开对话框后,按下确实就会上传,而且如果多选文件也会反复调用后端接口来完成上传。因为项目需要,所以要实现手动上传,和一次性上传多个文件(调用一次后端接口)在实现这个功能时,我翻阅了很多博客,可能是因为版本原因,很多代码都无用,最后还是通过翻阅官方文档,才最终实现。..._antd upload

sqlite3 环境搭建_sqlite 部署-程序员宅基地

文章浏览阅读246次。注意 第一步在一个文件下打开终端然后 sqlite3 student.db(创建一个数据库),然后再create stu。callback 回调函数 (只有sql为查询语句的时候,才会执行此语句)6--删除一列(sqlite3 不支持) 用下面方法。功能 :打开sqlite 数据库。功能 :关闭sqlite 数据库。基本sql命令,不以 . 夹头,db:指向sqlite句柄的指针。将新表的名字改为原来表的名字。sqlite3的基本命令。功能:执行一条sql语句。以 . 开头的命令。_sqlite 部署

canal-adapter趟坑实践:canal-server的kafka SASLPLAIN方式鉴权适配_canal adapter kafka sasl-程序员宅基地

文章浏览阅读1.4w次。前言canal-server同步到kafka本身是支持Kerberos方式的鉴权的,但是鉴于项目现在使用的kafka集群使用的是SASL/PLAIN的鉴权方式,所以需要对canal-server同步kafka做一下适配改造。准备kafka SASL/PLAIN鉴权的搭建我参考的这篇文章kafka SASL/PLAIN鉴权的搭建了解如何使用java向以SASL/PLAIN方式鉴权的kafk..._canal adapter kafka sasl

随便推点

华为交换机 配置练习2 trunk_适合练习用的华为交换机-程序员宅基地

文章浏览阅读3.1k次。练习内容:给出上图拓扑图,配置两个交换机后,使得pc14可直接ping通pc17 ,给定各pc的ip和掩码如下pc14: 192.168.0.1 255.255.255.0 pc15: 192.168.0.2 255.255.255.0pc16: 192.168.0.3 255.255.255.0 pc17: 192.168.0.4 255.255.25..._适合练习用的华为交换机

java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoa解决方案-程序员宅基地

文章浏览阅读640次,点赞8次,收藏11次。java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoa解决方案_java.lang.classnotfoundexception: org.springframework.web.context.contextloa

Autodesk官方卸载工具软件安装教程-程序员宅基地

文章浏览阅读1.4w次,点赞9次,收藏10次。Autodesk卸载工具是一个专门用于Autodesk软件的卸载工具,可以自动识别电脑中的所有Autodesk软件,只需一键点击就能将Autodesk的软件完美卸载,并且不保留任何痕迹,这款卸载工具就可以帮助用户全面卸载Autodesk软件。_autodesk官方卸载工具

JDBC报错:Cannot find class: com.mysql.jdbc.Driver-程序员宅基地

文章浏览阅读4.9k次。1.配置书写错误:配置文件value值引号内不能有空格,属性文件配置信息末尾不能有空格(1)打开属性文件中com.mysql.jdbc.Driver后发现多了一个空格(如下我标出了),所以写属性文件时一定别多输入多余的空格了。 jdbc.driverClassName=com.mysql.jdbc.Driver(此处有空格)(2)配置文件中的value值的" "号中前面或..._cannot find class: com.mysql.jdbc.driver

软件常用术语_软件术语-程序员宅基地

文章浏览阅读1.8k次。软件常用术语,免得你面对各种设计模式头发晕_软件术语

Machine Learning 2 - 非线性回归算法分析_非线性回归分析方法-程序员宅基地

文章浏览阅读2.8k次。2017-08-02@erixhao 技术极客TechBoosterAI 机器学习第二篇 - 非线形回归分析。我们上文深入本质了解了机器学习基础线性回归算法后,本文继续研究非线性回归。非线性回归在机器学习中并非热点,并且较为小众,且其应用范畴也不如其他广。鉴于此,我们本文也将较为简单的介绍,并不会深入展开。非线性回归之后,我们会继续经典机器学习算法包括决策_非线性回归分析方法

推荐文章

热门文章

相关标签