赞
踩
val result = lock(lock, {sharedResource.operation()} )
1.3、高阶函数的使用
在上面的两个例子中,我们出现了str.sumBy{ it.toInt }
这样的写法。其实这样的写法在前一章节Lambda使用
中已经讲解过了。这里主要讲高阶函数中对Lambda语法
的简写。
从上面的例子我们的写法应该是这样的:
str.sumBy( { it.toInt } )
但是根据Kotlin
中的约定,即当函数中只有一个函数作为参数,并且您使用了lambda
表达式作为相应的参数,则可以省略函数的小括号()
。故而我们可以写成:
str.sumBy{ it.toInt }
还有一个约定,即当函数的最后一个参数是一个函数,并且你传递一个lambda
表达式作为相应的参数,则可以在圆括号之外指定它。故而上面例2
中的代码我们可写成:
val result = lock(lock){
sharedResource.operation()
}
我们先看了一个例子:
// 源代码
fun test(a : Int , b : Int) : Int{
return a + b
}
fun sum(num1 : Int , num2 : Int) : Int{
return num1 + num2
}
// 调用
test(10,sum(3,5)) // 结果为:18
// lambda
fun test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
return a + b.invoke(3,5)
}
// 调用
test(10,{ num1: Int, num2: Int -> num1 + num2 }) // 结果为:18
可以看出上面的代码中,直接在我的方法体中写死了数值,这在开发中是很不合理的,并且也不会这么写。上面的例子只是在阐述Lambda
的语法。接下来我另举一个例子:
例:传入两个参数,并传入一个函数来实现他们不同的逻辑
private fun resultByOpt(num1 : Int , num2 : Int , result : (Int ,Int) -> Int) : Int{
return result(num1,num2)
}
fun main() {
val result1 = resultByOpt(1,2){
num1, num2 -> num1 + num2
}
val result2 = resultByOpt(3,4){
num1, num2 -> num1 - num2
}
val result3 = resultByOpt(5,6){
num1, num2 -> num1 * num2
}
val result4 = resultByOpt(6,3){
num1, num2 -> num1 / num2
}
println(“result1 =
r
e
s
u
l
t
1
"
)
p
r
i
n
t
l
n
(
"
r
e
s
u
l
t
2
=
result1") println("result2 =
result1")println("result2 = result2”)
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("result4 = result4”)
}
输出结果为:
result1 = 3
result2 = -1
result3 = 30
result4 = 2
这个例子是根据传入不同的Lambda
表达式,实现了两个数的+、-、*、/
。
下面介绍几个Kotlin
中常用的标准高阶函数。熟练的用好下面的几个函数,能减少很多的代码量,并增加代码的可读性。下面的几个高阶函数的源码几乎上都出自Standard.kt
文件
这个函数不是一个高阶函数,它只是一个抛出异常以及测试错误的一个普通函数。
此函数的作用:显示抛出
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.
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()
}
这两个函数的区别在于:
with
是正常的高阶函数,T.run()
是扩展的高阶函数。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的其他一些操作
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
**其实上面说了这么多,钱是永远赚不完的,在这个知识付费的时代,知识技能提升才是是根本!我作为一名8年的高级工程师,知识技能已经学习的差不多。**在看这篇文章的可能有刚刚入门,刚刚开始工作,或者大佬级人物。
像刚刚开始学Android开发小白想要快速提升自己,最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以这里分享一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。
这么重要的事情说三遍啦!点赞+点赞+点赞!
第一章、热修复设计
第二章、插件化框架设计
第三章、组件化框架设计
第四章、图片加载框架
第五章、网络访问框架设计
第六章、RXJava 响应式编程框架设计
第七章、IOC 架构设计
第八章、Android 架构组件 Jetpack
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
GpTrpU-1712143321397)]
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。