我们对这几处的标记都清楚后我们具体看看run、with、apply、also、let、takeIf、takeUnless、repeat的功能。
/**
* Calls the specified function [block] and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
/**
* 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的用法如下:
val person = Person()
person.run {
age = 1
sex = 3
}
var e = run{
var a =""
2+3
}
class Person(var name: String = "", var age: Int = 0, var sex: Int = 0)
T.run是扩展函数,任何对象都可以调用,大括号内可以直接调用对象的属性和方法。
run:返回大括号内最后一行
注:有的文章中说可以使用return返回,如下:
var e = run{
var a =""
return 2+3
}
但我这无法编译通过,有可能是版本的问题。
/**
* Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
我们发现with也不是扩展函数,而且有2个参数,返回block函数的返回值
用法:
with(person) {
age = 1
this.sex = 3
}
1、block函数内this代表with的参数,所以可以直接调用persion的属性、方法
2、从用法上我们发现persion不能为null
3、this可以省略
public inline fun T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
1、apply返回的是对象本身
2、block函数内this代表对象本身
使用:
val newPersion = person.apply { this.age = 0}
.apply { sex =2 }
是不是感觉可以替代Builder模式
@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对比发现是block的参数不一样,apply是T.(),also是(T),所以使用是不同的:
val b = person.also {it.age =4}
.also { it.sex = 5 }
also中不可以直接调用对象的属性和方法,通过it调用,it代表当前对象
@kotlin.internal.InlineOnly
public inline fun T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
和also对比不同是返回值不同,also返回当前对象,let返回block函数最后一行
@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
}
如果函数返回值是true则返回对象本身,否则返回null
使用:
var p = person.takeIf { true }
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun T.takeUnless(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (!predicate(this)) this else null
}
takeUnless和takeif相反,使用:
var p = person.takeUnless { true }
@kotlin.internal.InlineOnly
public inline fun repeat(times: Int, action: (Int) -> Unit) {
contract { callsInPlace(action) }
for (index in 0 until times) {
action(index)
}
}
就是封装了一个for循环,使用:
repeat(4){
//it代表 0..3
print(it)
}
看完上面的是不是特别晕,感觉没什么区别啊,下面总结下他们的区别和相同点,我觉得没必要背下来,我们需要通过源码理解他的意思。
1、他们都是作用域函数,都提供了内部作用域
2、函数前没有T的是普通函数(run,with)和有T的是扩展函数(T.run,T.also 等)
3、参数不同
block:T.() 参数当前对象,this可以省略
blcok:(T): 参数当前对象,it表示当前对象,不可省略
无参数的形式:block: ()
4、返回值不同:
return block():返回block函数最后一行
return this:返回当前对象
原来的写法:
var person = Person()
person.age = 1
person.name = ""
person.sex = 4
let写法 :
person.let {
it.name = ""
it.age = 1
it.sex = 3
}
run写法(推荐):
person.run {
name = ""
age = 1
sex = 3
}
系统属性:
textView.run {
textSize = 12F
text = ""
}
是不是run的写法更“漂亮”。
if(null != textView){
print("textView is not null")
add()
}
run、let写法:
textView?.let {
print("textView is not null")
add()
}
textView?.run {
print("textView is not null")
add()
}