作用域函数
在 Standard.kt 标准库中提供了一些便捷的内置高阶函数,可以帮助我们写出更简洁高效的代码。这些函数都是在一个对象上执行一个代码块,形成一个临时作用域可以访问该对象而无需其名称,不同的是这个对象在代码块中如何使用以及整个表达式的返回值是什么。由于是 inline 内联函数,优化了调用函数出入栈的性能开销。
| 参数 T.() :Lambda的接收者,即 this。 直接使用调用者对象public的类成员(配置自身) | 参数 T?:Lambda的参数,即 it。 将调用者对象当作参数使用(额外做事) | 无参数 | 返回值 T?:调用者对象。 基于原始对象进行链式调用。 | apply | also | | 返回值 R?:Lambda的值。 基于新值进行链式调用。 | run with(无法链式调用) | let | run |
apply
说明:调用该对象的类成员,返回该对象。
场景:对该对象的成员属性和成员函数进行一系列的调用,创建实例并配置(对已有的实例配置选with)。由于最后返回该对象可以链式调用,一次操作过多可以将同类型操作分批写在不同代码块里让视觉上更直观。
//源码
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
val student = Student()
//未使用(每次都要使用变量名调用成员)
student.id = 123
student.name = "张三"
student.study()
student.rest()
//使用后(直接调用类成员)
val student = Student().apply {
id = 123456
name = "李四"
}.apply {
study()
rest()
}
also
说明:将该对象当做参数使用,返回该对象。
场景:将该对象当作参数进行一系列操作。由于最后返回该对象可以链式调用,一次操作过多可以将同类型操作分批写在不同代码块里让视觉上更直观。
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
val student = Student()
//未使用(每次都要用实例名调用,针对该对象的一系列操作挤在一起)
student.setname("张三")
growingUp(student.age)
student.study()
setLeader(student)
//使用后(使用it调用更便于阅读,分类隔开写代码视觉上更直观)
student.also {
it.setname("张三")
it.study()
}.also {
growingUp(it.age)
setLeader(it)
}
let
说明:将该对象当做参数使用,返回Lambda的值。
场景:①将该对象当作参数进行一系列操作;②对可空类型对象的多次使用做统一的 null 判断。
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
val student = Student()
//未使用(每次都要用实例名调用)
student.setname("张三")
growingUp(student.age)
student.study()
setLeader(student)
//使用后(使用it更便于阅读)
student.let {
it.setname("张三")
it.study()
growingUp(it.age)
setLeader(it)
}
//未使用(每次都要使用安全调用符)
student?.setName("张三")
student?.setAge(18)
student?.study()
//使用后(只需要使用一次安全调用符)
student?.let {
it.setName("张三")
it.setAge(18)
it.study()
}
with
说明:调用该对象的类成员,返回Lambda的值。不是扩展函数。
场景:对该对象的成员属性和成员函数进行一系列的调用,对已有的实例进行配置(创建并配置选apply)。
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
with(recyclerView) {
layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
adapter = mAdapter
}
run
说明:①调用该对象的类成员,返回Lambda的值。②无参数,返回Lambda的值。
场景:①②?
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
其他库函数?
repeat
原理:将 action 函数执行 times 次。
public inline fun repeat(times: Int, action: (Int) -> Unit) {
contract { callsInPlace(action) }
for (index in 0 until times) {
action(index)
}
}
repeat(6) {
print("A$it,") //打印:A1,A2,A3,A4,A5,A6
}
takeIf
说明:lambda 返回 true 则返回调用者对象,否则返回 null。
场景:判断是否满足条件,再决定是否赋值或者执行操作。和 if 相似,作用于实例上避免了临时变量赋值的麻烦。
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (predicate(this)) this else null
}
val num: Int = 3
println(num.takeIf { it > 5 }.toString()) //打印:null
takeUnless
原理:功能和 takeIf 相反,predicate 返回 false 则返回调用者对象,否则返回 null。
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (!predicate(this)) this else null
}
val num: Int = 3
println(num.takeUnless { it > 5 }.toString()) //打印:5
TODO?
用来标记待办,会抛异常,可以指定异常原因。
public inline fun TODO(): Nothing = throw NotImplementedError()
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")
|