Kotlin标准库中有一些非常实用的扩展函数。
/**
* Calls the specified function [block] with `this` value as its receiver and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
run是任何类型T的通用扩展函数,run中执行了返回类型为R的扩展函数block,最终返回该扩展函数的结果。
在run函数中我们拥有一个单独的作用域,能够重新定义一个新变量,并且它的作用域只存在于run函数中。
fun testPayFoo() {
val nickName = "Perfect"
run {
val nickName = "PAYZY"
println(nickName)
}
println(nickName)
}
fun main() {
testPayFoo()
}
PAYZY
Perfect
并且它返回范围内最后一个对象。
例子:
data class StuA(val name: String)
fun testPayFoo2() {
val run = run {
println("test return")
StuA("PAYZY")
}
println(run)
}
fun main() {
testPayFoo2()
}
test return
StuA(name=PAYZY)
/**
* Calls the specified function [block] with `this` value as its argument and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
let与apply类似,唯一不同的是返回值:apply返回的是原来的对象,而let返回的是闭包里面的值。let同样限制了变量的作用域。
data class Student(val age: Int)
class PayKot {
val stu: Student? = Student(2)
fun dealStu() {
val result = stu?.let {
println(it.age)
it.age
}
println("result:$result")
}
}
fun main() {
PayKot().dealStu()
}
2
result:2
also是Kotlin1.1版本中新加入的内容,它像是let和apply函数的加强版。
/**
* Calls the specified function [block] with `this` value as its argument and returns `this` value.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
与apply一致,它的返回值是该函数的接收者。
data class PayStudent(val age: Int)
class PayZKot {
val student: PayStudent? = PayStudent(666)
var age = 0
fun dealStu() {
val result = student?.also { stu ->
this.age += stu.age
println(this.age)
println(stu.age)
this.age
}
println("result:$result")
}
}
fun main() {
PayZKot().dealStu()
}
666
666
result:PayStudent(age=666)
在上面代码中,将其隐式参数指定为stu,假设 student?不为空,会返回student,并且总年龄 this.age增加了。
主要注意的是:如果使用apply,由于其内部是一个扩展函数,this将指向stu而不是PayZKot,此时就无法调用到PayKot下的age。
如果不仅仅想判空,还要加入条件,这时let就有些不足。这时可以使用takeIf 。
/**
* Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun T.takeIf(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (predicate(this)) this else null
}
这个函数也是在Kotlin1.1中新增加的。当接收器满足某些条件时才会执行。
例子:
class PayTestTakeIf {
val stuA: PayStudent2? = PayStudent2(55)
val stuB: PayStudent2? = PayStudent2(5)
fun dealStu() {
val let = stuA?.takeIf { it.age > 10 }?.let {
println(it.age)
it.age
}
println("let:$let")
val takeIf = stuB?.takeIf { it.age > 10 }
println(takeIf)
}
}
fun main() {
PayTestTakeIf().dealStu()
}
55
let:55
null
参考Kotlin核心编程