println(“result3 =  r e s u l t 3 " ) p r i n t l n ( " r e s u l t 4   =   result3") println("result4 =  result3")println("result= result4”)
}

输出结果为:

result1 = 3
result2 = -1
result3 = 30
result4 = 2

这个例子是根据传入不同的Lambda表达式,实现了两个数的+、-、*、/

三、常用的标准高阶函数介绍

下面介绍几个Kotlin中常用的标准高阶函数。熟练的用好下面的几个函数,能减少很多的代码量,并增加代码的可读性。下面的几个高阶函数的源码几乎上都出自Standard.kt文件

3.1、TODO函数

这个函数不是一个高阶函数,它只是一个抛出异常以及测试错误的一个普通函数。

此函数的作用:显示抛出NotImplementedError错误。NotImplementedError错误类继承至Java中的Error。我们看一看他的源码就知道了:

public class NotImplementedError(message: String = “An operation is not implemented.”) : Error(message)

TODO函数的源码

@kotlin.internal.InlineOnly
public inline fun TODO(): Nothing = throw NotImplementedError()

@kotlin.internal.InlineOnly
public inline fun TODO(reason: String): Nothing = 
throw NotImplementedError(“An operation is not implemented: $reason”)

举例说明:

fun main(args: Array) {
TODO(“测试TODO函数,是否显示抛出错误”)
}

输出结果为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果调用TODO()时,不传参数的,则会输出An operation is not implemented.

3.2 、run()函数

run函数这里分为两种情况讲解,因为在源码中也分为两个函数来实现的。采用不同的run函数会有不同的效果。

3.2.1、run()

我们看下其源码:

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

关于contract这部分代码小生也不是很懂其意思。在一些大牛的blog上说是其编辑器对上下文的推断。但是我也不知道对不对,因为在官网中,对这个东西也没有讲解到。不过这个单词的意思是契约,合同等等意思。我想应该和这个有关。在这里我就不做深究了。主要讲讲run{}函数的用法其含义。

这里我们只关心return block()这行代码。从源码中我们可以看出,run函数仅仅是执行了我们的block(),即一个Lambda表达式,而后返回了执行的结果。

用法1:

当我们需要执行一个代码块的时候就可以用到这个函数,并且这个代码块是独立的。即我可以在run()函数中写一些和项目无关的代码,因为它不会影响项目的正常运行。

例: 在一个函数中使用

private fun testRun1() {
val str = “kotlin”

run{
val str = “java”   // 和上面的变量不会冲突
println(“str = $str”)
}

println(“str = $str”)
}

输出结果:

str = java
str = kotlin

用法2:

因为run函数执行了我传进去的lambda表达式并返回了执行的结果,所以当一个业务逻辑都需要执行同一段代码而根据不同的条件去判断得到不同结果的时候。可以用到run函数

例:都要获取字符串的长度。

val index = 3
val num = run {
when(index){
0 -> “kotlin”
1 -> “java”
2 -> “php”
3 -> “javaScript”
else -> “none”
}
}.length
println(“num = $num”)

输出结果为:

num = 10

3.2.2、T.run()

其实T.run()函数和run()函数差不多,关于这两者之间的差别我们看看其源码实现就明白了:

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

从源码中我们可以看出,block()这个函数参数是一个扩展在T类型下的函数。这说明我的block()函数可以可以使用当前对象的上下文。所以当我们传入的lambda表达式想要使用当前对象的上下文的时候,我们可以使用这个函数。

例:

val str = “kotlin”
str.run {
println( “length =  t h i s . l e n g t h "   ) p r i n t l n (   " f i r s t   =   {this.length}" ) println( "first =  this.length)println( "first = {first()}”)
println( “last = ${last()}” )
}

输出结果为:

length = 6
first = k
last = n

在其中,可以使用this关键字,因为在这里它就代码str这个对象,也可以省略。因为在源码中我们就可以看出,block()就是一个T类型的扩展函数。

这在实际的开发当中我们可以这样用:

例: 为TextView设置属性。

val mTvBtn = findViewById(R.id.text)
mTvBtn.run{
text = “kotlin”
textSize = 13f

}

3.3 、with()函数

其实with()函数和T.run()函数的作用是相同的,我们这里看下其实现源码:

public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}

这两个函数的区别在于:

  1. with是正常的高阶函数,T.run()是扩展的高阶函数。
  2. with函数的返回值指定了receiver为接收者。

例:实现上面的T.run()函数的列子

val str = “kotlin”
with(str) {
println( “length =  t h i s . l e n g t h "   ) p r i n t l n (   " f i r s t   =   {this.length}" ) println( "first =  this.length)println( "first = {first()}”)
println( “last = ${last()}” )
}

输出结果为:

length = 6
first = k
last = n

例:当我的对象可为null的时候,看两个函数之间的便利性

val newStr : String? = “kotlin”

with(newStr){
println( “length =  t h i s ? . l e n g t h "   ) p r i n t l n (   " f i r s t   =   {this?.length}" ) println( "first =  this?.length)println( "first = {this?.first()}”)
println( “last = ${this?.last()}” )
}

newStr?.run {
println( “length =  l e n g t h "   ) p r i n t l n (   " f i r s t   =   length" ) println( "first =  length)println( "first = {first()}”)
println( “last = ${last()}” )
}

从上面的代码我们就可以看出,当我们使用对象可为null时,使用T.run()比使用with()函数从代码的可读性与简洁性来说要好一些。当然关于怎样去选择使用这两个函数,就得根据实际的需求以及自己的喜好了。

3.4、T.apply()函数

我们先看下T.apply()函数的源码:

public inline fun  T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}

T.apply()源码中在结合前面提到的T.run()函数的源码我们可以得出,这两个函数的逻辑差不多,唯一的区别是T,apply执行完了block()函数后,返回了自身对象。而T.run是返回了执行的结果。

故而: T.apply的作用除了实现能实现T.run函数的作用外,还可以后续的再对此操作。下面我们看一个例子

例:为TextView设置属性后,再设置点击事件等

val mTvBtn = findViewById(R.id.text)
mTvBtn.apply{
text = “kotlin”
textSize = 13f

}.apply{
// 这里可以继续去设置属性或一些TextView的其他一些操作
}.apply{
setOnClickListener{ … }
}

或者:设置为Fragment设置数据传递

// 原始方法
fun newInstance(id : Int , name : String , age : Int) : MimeFragment{
val fragment = MimeFragment()
fragment.arguments?.putInt(“id”,id)
fragment.arguments?.putString(“name”,name)
fragment.arguments?.putInt(“age”,age)

return fragment
}

// 改进方法
fun newInstance(id : Int , name : String , age : Int) = MimeFragment().apply {
arguments = Bundle()
arguments?.putInt(“id”,id)
arguments?.putString(“name”,name)
arguments?.putInt(“age”,age)
}

3.5、T.also()函数

关于T.also函数来说,它和T.apply很相似,。我们先看看其源码的实现:

public inline fun  T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}

从上面的源码在结合T.apply函数的源码我们可以看出: T.also函数中的参数block函数传入了自身对象。故而这个函数的作用是用用block函数调用自身对象,最后在返回自身对象

这里举例一个简单的例子,并用实例说明其和T.apply的区别

例:

“kotlin”.also {
println(“结果:KaTeX parse error: Expected 'EOF', got '}' at position 24: …("-java")}") }̲.also { print…{it.plus(”-php")}")
}

“kotlin”.apply {
println(“结果:KaTeX parse error: Expected 'EOF', got '}' at position 26: …("-java")}") }̲.apply { prin…{this.plus(”-php")}")
}

他们的输出结果是相同的:

结果:kotlin-java
结果:kotlin-php

结果:kotlin-java
结果:kotlin-php

从上面的实例我们可以看出,他们的区别在于,T.also中只能使用it调用自身,而T.apply中只能使用this调用自身。因为在源码中T.also是执行block(this)后在返回自身。而T.apply是执行block()后在返回自身。这就是为什么在一些函数中可以使用it,而一些函数中只能使用this的关键所在

3.6、T.let()函数

public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}

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

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。如有需要获取完整的资料文档的朋友点击我的GitHub免费获取。

61)]

七大模块学习资料:如NDK模块开发、Android框架体系架构…

[外链图片转存中…(img-czD3DSer-1711189290962)]

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。如有需要获取完整的资料文档的朋友点击我的GitHub免费获取。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐