前言
正文
run()
@kotlin.internal.InlineOnly public inline fun <T, R> T.run(block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() }
作用:执行一个代码块并返回其结果。
run()在内部运行对象是通过this访问的,当您想要调用对象的方法而不是将其作为参数传递时,这是很有用的。
使用场景
适用于let,with函数任何场景。
因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理。
简单使用
//使用1 val website: String = "91es.com"; var name = website.run { Log.d(TAG, "run : " + isEmpty()) Log.d(TAG, "run : $length"); this }; Log.d(TAG, "name : $name") //使用2 private fun test(): String { return Thread.currentThread().name; } var test = run { test() } Log.d(TAG, "test : $test")
执行后结果
run : false run : 8 name : 91es.com test : main
得出如下结果:
-
run()内部可通过this获取调用对象,并调用其方法。
-
run()返回值为最后一行的值或者指定的return的表达式。
-
run()执行在主线程中。
apply()
@kotlin.internal.InlineOnly public inline fun <T> T.apply(block: T.() -> Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() return this }
对比run(),apply()不同的是,先是调用了block()函数,然后返回当前的调用者对象this。
apply在对象上执行代码块并返回对象本身。在块内部,对象被this引用。这个函数对于初始化对象很方便。
使用场景
整体作用功能和run函数很像,唯一不同点就是它返回的值是对象本身,而run函数是一个闭包形式返回,返回的是最后一行的值。
正是基于这一点差异它的适用场景稍微与run函数有点不一样。apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到,这种情景非常常见。特别是在我们开发中会有一些数据model向View model转化实例化的过程中需要用到。
简单使用
var list = ArrayList<Int>(); list = list.apply { add(1) add(2) add(3) add(4) } Log.d(TAG, "list : $list")
执行后结果
list : [1, 2, 3, 4]
let()
@kotlin.internal.InlineOnly public inline fun <T, R> T.let(block: (T) -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block(this) }
对比上面的run()和apply()等,let()把调用对象直接传入了block(),并返回block(this)的值。
在let中,用it表示引用对象,并可调用其方法,it不可省略。
object.let{ it.todo()//在函数体内使用it替代object对象去访问其公有的属性和方法 ... } //另一种用途 判断object为null的操作 //表示object不为null的条件下,才会去执行let函数体 object?.let{ it.todo() } var list :ArrayList<Int>? = ArrayList() list?.let{ it.add(1) it.add(2) } print(list)
使用场景
适合用于处理不为null的操作场景。
简单使用
var list = ArrayList<Int>(); list.let { it.add(1) it.add(2) it.add(3) it.add(4) } Log.d(TAG, "list : $list")
执行结果
list : [1, 2, 3, 4]
with()
@kotlin.internal.InlineOnly public inline fun <T, R> with(receiver: T, block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return receiver.block() }
with函数不是扩展函数,是将某对象作为函数的参数,在函数块内可以通过this指代该对象,返回值为函数块的最后一行或指定return表达式。
使用场景
适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法或者属性即可,经常用于Android中RecycleView中onBinderViewHolder中,数据model的属性映射到UI上。
简单使用
val student = Student("91大神", 20) //result返回with()中最后一行或return值 val result = with(student) { Log.d(TAG, "name : $name") Log.d(TAG, "age : $age") 91 } Log.d(TAG, "result : $result")
执行结果
name : 91大神 age : 20 result : 91
with怎么感觉跟run有点类似,但调用方式不太一样。
val website: String = "91es.com"; //使用run var name1 = website.run { Log.d(TAG, "run : " + isEmpty()) Log.d(TAG, "run : $length"); this }; Log.d(TAG, "run name1 : $name1") //使用with var name2 = with(website) { Log.d(TAG, "with : " + isEmpty()) Log.d(TAG, "with : $length"); this } Log.d(TAG, "with name2 : $name2")
执行结果一样
run : false run : 8 run name1 : 91es.com with : false with : 8 with name2 : 91es.com
also()
@kotlin.internal.InlineOnly @SinceKotlin("1.1") public inline fun <T> T.also(block: (T) -> Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block(this) return this }
跟let有点像,但最后返回的是this。
使用场景
适用于let函数的任何场景。一般可用于多个扩展函数链式调用。
简单使用
var name = website.also { Log.d(TAG, "isEmpty : " + it.isEmpty()) Log.d(TAG, "length : " + it.length) } Log.d(TAG, "also name : $name")
执行结果
isEmpty : false length : 8 also name : 91es.com
参考文章
-
《Kotlin从入门到进阶实战 - 陈光剑 》
-
《》
-
《