标准库中的作用域函数
在 Standard.kt 标准库中提供了一些便捷的内置高阶函数,可以帮助我们写出更简洁高效的代码。这些函数都是在一个对象上执行一个代码块,形成一个临时作用域可以访问该对象而无需其名称,不同的是这个对象在代码块中如何使用以及整个表达式的返回值是什么。由于是 inline 内联函数,优化了调用函数出入栈的性能开销。
内置高阶函数 | 说明 | 使用场景 |
---|---|---|
apply |
在调用处:调用该对象this的类成员,返回该对象。 参数: T.() :在applay源码里将接受者对象this(T)作为隐士参数 传递给lambda,没有其他的参数。 在lambda表达式实现作用域内,隐士参数 this,使用this可以直接访问调用者对象T(自定义对象/this)的类成员 返回值: T:即返回调用者对象(自定义对象/this)本身,可基于原始对象进行链式调用。 | 对该对象的成员属性和成员函数进行一系列的调用,创建实例并配置(对已有的实例配置选with)。由于最后返回该对象可以链式调用,一次操作过多可以将同类型操作分批写在不同代码块里让视觉上更直观。 |
with |
参数: T.() :在with源码可知, 即 this,直接访问调用者对象(自定义对象/this)的类成员(配置自身)返回值 返回值:R:即返回一个值,可基于新值进行链式调用。 | 对该对象的成员属性和成员函数进行一系列的调用,对已有的实例进行配置(创建并配置选apply)。 |
also |
将该对象当做参数使用,返回该对象。 参数:(T) :通过also源码可知将调用者对象this当作lambda表达式的参数进行回调 调用处:在调用处通过lambda表达式具体实现通过lambda的参数it (调用者对象)调用调用者对象的成员或者做额外的事。 返回值:T:即返回调用者对象本身,可基于原始对象进行链式调用。 | 将该对象当作参数进行一系列操作。由于最后返回该对象可以链式调用,一次操作过多可以将同类型操作分批写在不同代码块里让视觉上更直观。 |
let |
将该对象当做参数使用,返回Lambda的值。 参数:(T) :在let源码可知 把调用者对象this作为参数T进行回调 在调用处,通过lambda表达式具体实现,lambda的参数it(默认值)就是当前对象T 返回值:R:在let源码可知,把一个新值R作为返回值. 在调用处通过lambda表达式具体实现,把lamba最后一行作为返回值。 | ①将该对象当作参数进行一系列操作; ②对可空类型对象的多次调用做统一的 null 判断。 |
run |
调用该对象的类成员,返回Lambda的值。 参数: T.() :通过run源码可知,将接受者对象this 传递给lambda表达式的参数 在调用处:在lambda表达式作用域的参 this,通过this直接访问调用者对象(自定义对象/this)的类成员(配置自身)返回值 返回值:R:即返回一个值,可基于新值进行链式调用。 | |
run |
执行若干代码,返回Lambda的值。不是扩展函数。 |
apply函数
对象实例初始化时需要对对象中的属性进行赋值 & 返回该对象
官方apply
inline fun <T> T.apply(block: T.() -> Unit): T {
//block()
//return this
//或者
block.invoke(this) //这里将接受者对象this(T)作为隐士参数 传递给lambda 没有其他的额外参数传递
return this //返回 接受者对象this(T)
}
apply与run函数类似,但区别在于返回值不同:
run函数:返回最后一行的值 / 表达式
apply函数:返回传入的对象的本身
package com.my.runalone_higherorderfunction.bean
import android.util.Log
class Person(var name_:String?="上帝",var age_:Int?=0) {
val TAG="HigherOrderFunctionSuspendActivity"
var name:String? = name_
var age:Int? = age_
var sex:Int = 0
override fun toString(): String {
return "name:$name, age:$age, sex:$sex"
}
public fun study(){
Log.e(TAG, "$name is studying" )
}
}
class HigherOrderFunctionSuspendActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?){
/**
* 官方apply
inline fun <T> T.apply(block: T.() -> Unit): T {
//block()
//return this
//或者
block.invoke(this) //这里将接受者对象this(T)作为隐士参数 传递给lambda 没有其他的额外参数传递
return this //返回 接受者对象this(T)
}
*/
val person= Person(name_="张三")
person.apply(block={
Log.e(TAG, "apply 输出结果this=${this.toString()}") //apply 输出结果this=name:张三, age:0, sex:0
//直接访问Person的属性
this.age=20 //this可以省略
this.sex=1 //this可以省略
}).apply {
this.study() //张三 is studying
}
}
}
with函数
调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可
需要调用同一个对象的多个方法 / 属性
/**
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
//var result:R = receiver.block()
//return result
var result:R = block.invoke(receiver)
return result
}
*/
val withResult:Int = with(receiver = person, block = {
Log.e(TAG, "with 输出当前对象this=${this} ")// with 输出当前对象this=name:张三, age:20, sex:1
this.name_ = "张四"
this.age_ = 21
this.sex = 0
123//把lambda最后一行作为返回值
})
Log.e(TAG, "withResult=${withResult}") // withResult=123
自定义myWith1/2/3/4/5/6/7(...)函数
Extend.kt
inline fun <T, R> myWith1(receiver: T, block: T.(Any) -> R): R {
var result:R = block.invoke(receiver,101)
return result
}
inline fun <T, R> T.myWith2( block: T.(Any) -> R): R {
var result:R = block.invoke(this,"angleBody")
return result
}
inline fun <T, R> T.myWith3( block: T.(Any) -> R): R {
var result:R = block.invoke(this,12)
return result
}
inline fun <T, R> myWith4( block: (T,Any) -> R): R {
val person= Person(name_="NIUBI",age_=233)
var result:R = block.invoke( person as T ,"niubi")
return result
}
val TAG="HigherOrderFunctionSuspendActivity"
inline fun <T, R> T.myWith5( block: T.(T,Any) -> R): R {
Log.e(TAG, "T.myWith5 输出当前对象this=${this}") //T.myWith5 输出当前对象this=name:天使, age:12, sex:1
val person= Person(name_="newPer",age_=23) as T
var result:R = block.invoke(this,person,true)
return result
}
inline fun<T,R> T.myWith6(block:(T)->R):R{
// val result:R = block(this)
// return result
val result:R = block.invoke(this)//b把接受者对象this 作为参数进行传递 回调给lambda
return result
}
inline fun <T, R> T.myWith7( block: T.(T) -> R): R {
//var result:R = receiver.block()
//return result
var result:R = block.invoke(this,this)
return result
}
class HigherOrderFunctionSuspendActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?){
val myWith1Result :String = myWith1(receiver = person,block={
Log.e(TAG,"myWith1 输出当前对象this=${this}, it=$it") //myWith1 输出当前对象this=name:张三, age:20, sex:1, it=101
this.name="张四"
this.age=21
"Androider" //把lambda最后一行作为返回值
})
Log.e(TAG, "myWith1Result=${myWith1Result}") //myWith1Result=Androider
val myWith2Result :Person = person.myWith2(block={
Log.e(TAG,"myWith2 输出当前对象this=${this}, it=$it") //myWith2 输出当前对象this=name:张四, age:21, sex:1, it=angleBody
this.name=it as String
this.age=22
this //把lambda最后一行作为返回值
})
Log.e(TAG, "myWith2Result=${myWith2Result}") //myWith2Result=name:angleBody, age:22, sex:1
val myWith3Result: String= 100.myWith3(block = {
Log.e(TAG, "myWith3 输出当前对象this=${this}, it=$it") //myWith3 输出当前对象this=100, it=1.2
"FM.1080" //把lambda最后一行作为返回值
})
Log.e(TAG, "myWith3Result=${myWith3Result}") //myWith3Result=FM.1080
val myWith32Result: Person = person.myWith3(block = {
Log.e(TAG, "myWith3 输出当前对象this=${this}, it=$it") //myWith3 输出当前对象this=name:angleBody, age:22, sex:1, it=12
this.name="天使"
this.age=it as Int
this //把lambda最后一行作为返回值
})
Log.e(TAG, "myWith32Result=${myWith32Result}") //myWith32Result=name:天使, age:12, sex:1
val myWith4Result:Int = myWith4(block={pp:Person,str->
Log.e(TAG, "myWith4 输出当前对象pp=${pp}, str=$str") //myWith4 输出当前对象pp=name:NIUBI, age:233, sex:0, str=niubi
2024 //把lambda最后一行作为返回值
})
Log.e(TAG, "myWith4Result=${myWith4Result}") //myWith4Result=2024
Log.e(TAG, " 输出当前对象person=${person.toString()}") // 输出当前对象person=name:天使, age:12, sex:1
val myWith5Result:Boolean = person.myWith5(block={newP:Person,bo:Any->
Log.e(TAG, "myWith5 this=${this},输出当前对象newP=${newP},bo=$bo") //myWith5 this=name:天使, age:12, sex:1,输出当前对象newP=name:newPer, age:23, sex:0,bo=true
var isChild:Boolean=false
if(bo as Boolean){
isChild=true
}
isChild //把lambda最后一行作为返回值
})
Log.e(TAG, "myWith5Result=${myWith5Result}") //myWith5Result=true
val myWith6Result:Person = person.myWith6(block={
Log.e(TAG, "myWith6 输出lambda的参数it=${it}") //myWith6 输出lambda的参数it=name:天使, age:12, sex:1
it.name="llong"
it //把lambda最后一行作为返回值
})
Log.e(TAG, "myWith6Result=${myWith6Result}") // myWith6Result=name:llong, age:12, sex:1
val myWith7Result:String = person.myWith7(block={
Log.e(TAG, "myWith7 输出lambda的参数this=${this}, it=${it}") //myWith7 输出lambda的参数this=name:llong, age:12, sex:1, it=name:llong, age:12, sex:1
"kotlin"
})
Log.e(TAG, "myWith7Result=${myWith7Result}") //myWith7Result=kotlin
}
}
also函数
官方also
public inline fun <T> T.also(block: (T) -> Unit): T {
//block(this)
//return this
//或者
block.invoke(this) //没有返回值
return this // 把接受者对象T this 进行返回
}
also函数与let函数的区别:
let函数:返回值 = 最后一行 / return的表达式
also函数:返回值 = 传入的对象的本身
class HigherOrderFunctionSuspendActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?){
/**
官方also
public inline fun <T> T.also(block: (T) -> Unit): T {
//block(this)
//return this
//或者
block.invoke(this) //没有返回值
return this // 把接受者对象T this 进行返回
}
*/
val person= Person(name_="张三")
//使用also后(使用it调用更便于阅读,分类隔开写代码视觉上更直观)
person.also(block={
//没有指定参数名字,必须用it代指参数 it:Person = person
Log.e(TAG,"also 输出lambda的参数it=$it")
it.name="liuliang"
it.age=20
it.sex=0
Log.e(TAG, "输出结果it=${it.toString()}" ) //输出结果it=name=liuliang, age=20, sex=0
}) //点 左侧依然是person 对象 点右侧链式调用
.also {
it.study() //liuliang is studying
}
}
let函数
class HigherOrderFunctionSuspendActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?){
/**
inline fun <T, R> T.let(block: (T) -> R): R {
// val result:R = block(this)
// return result
val result:R =block.invoke(this)
return result
}
*/
//使用let后(使用it更便于阅读)
//使用let后(只需要使用一次安全调用符)
val letResult :Person? = person?.let(block = {
Log.e(TAG,"let1 输出当前对象it=$it") //let1 输出当前对象it=name:liuliang, age:20, sex:0
it.name = "李四"
it.age = 29
it.sex = 2
//Log.e(TAG, "输出结果it=${it.toString()}"
it //把lambda最后一行作为返回值
})
Log.e(TAG, "let1 输出结果letResult=${letResult}" ) //let1 输出结果letResult=name:李四, age:29, sex:2
val letResult2 :String? = letResult?.let(block={
Log.e(TAG,"let2 输出当前对象it=$it") //let2 输出当前对象it=name:李四, age:29, sex:2
it.name = "王五"
"fmf" //把lambda最后一行作为返回值
})
Log.e(TAG, "let2 输出结果letResult2=${letResult2}" ) //let2 输出结果letResult2=fmf
}
}
run函数
结合了let、with两个函数的作用,
1.调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可
2.定义一个变量在特定作用域内
3.统一做判空处理
/**
public inline fun <T, R> T.run(block: T.() -> R): R {
// return block()
//或者
val result:R = block.invoke(this)
return result
}
*/
val runResult:String = person.run(block = {
Log.e(TAG, "run 输出当前对象this=$this") // run 输出当前对象this=name:王五, age:29, sex:2
"run run go go" //把lambda最后一行作为返回值
})
Log.e(TAG, "run 输出结果runResult=${runResult}" ) // run 输出结果runResult=run run go go
自定义MyRun函数
Extend.kt
inline fun <T, R> T.myRun(block: T.() -> R): R {
// return block()
//或者
val result:R = block.invoke(this)
return result
}
inline fun <T, R> T.myRun3(block: () -> R): R {
// return block()
//或者
val result:R = block.invoke()
return result
}
inline fun <R> myRun4(block: () -> R): R {
// return block()
//或者
val result:R = block.invoke()
return result
}
class HigherOrderFunctionSuspendActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?){
val myRunResult:Boolean = person.myRun(block = {
Log.e(TAG, "myRun 输出当前对象this=$this") //myRun 输出当前对象this=name:王五, age:29, sex:2
false //把lambda最后一行作为返回值
})
Log.e(TAG, "myRun 输出结果myRunResult=${myRunResult}" ) //myRun 输出结果myRunResult=false
val myRun3Result:Boolean = person.myRun3(block = {
person.age = 20
person.sex = 1
true //把lambda最后一行作为返回值
})
Log.e(TAG, "myRun3Result 输出结果myRun3Result=${myRun3Result}" ) //myRun3Result 输出结果myRun3Result=true
val myRun4Result:Int = myRun4(block = {
456 //把lambda最后一行作为返回值
})
Log.e(TAG, "myRun4 输出结果myRun4Result=${myRun4Result}" ) //myRun4 输出结果myRun4Result=456
}
}
其他标准库函数
repeat
原理:将 action 函数执行 times 次。第一次的索引为0。
public inline fun repeat(times: Int, action: (Int) -> Unit) {
for (index in 0 until times) {
// action(index)
//或者
//通过源码可知 ,遍历集合tiems每一次, invoke传递一次参数index
action.invoke(index)
}
}
repeat(times=6,action={
// 输出lambda表达式参数it
Log.e(TAG, "A$it") //A0,A1,A2,A3,A4,A5
})
takeIf
说明:lambda 返回 true 则返回调用者对象,否则返回 null。
场景:判断是否满足条件,再决定是否赋值或者执行操作。和 if 相似,作用于实例上避免了临时变量赋值的麻烦。
inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
//return if (predicate(this)) this else null
val result:Boolean = predicate.invoke(this)//将调用者T=this(隐士)作为lambda表达式的参数就行回调
// 返回Boolean类型 :返回 true 则返回调用者对象this,否则返回 null
if(result){
return this
}
return null
}
val num6:Int=5
val takeIfResult = num6.takeIf(predicate = {
Log.e(TAG, "takeIf 输出lambda的回调参数it=$it") //takeIf 输出lambda的回调参数it=5
it > 3 //把lambda最后一行 it > 3=true 作为返回值 回调给takeIf源码
})
Log.e(TAG, "输出结果takeIfResult=${takeIfResult}") //输出结果takeIfResult=5
val num62:Int=5
val takeIfResult2 = num62.takeIf(predicate = {
Log.e(TAG, "takeIf 输出lambda的回调参数it=$it") //takeIf 输出lambda的回调参数it=5
it > 6 // 把lambda最后一行 it > 6=false 作为返回值 回调给takeIf源码
})
Log.e(TAG, "输出结果takeIfResult2=${takeIfResult2}") //输出结果takeIfResult2=null
takeUnless
原理:功能和 takeIf 相反,predicate 返回 false 则返回调用者对象,否则返回 null。
TODO
用来标记待办,会抛异常,可以指定异常原因。
public inline fun TODO(): Nothing = throw NotImplementedError()
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")
鸣谢
Kotlin - 作用域函数(apply、also、run、with、let)_kotlin let run apply with函数-CSDN博客