scope functions
Kotlin “scope functions” 允许改变一个变量的 scope,或者 range (作用域范围). 在此在Kotlin standard library中有五个类似方法: apply, run, with, let 和 also
已 run 为例说明:
fun myFun() {val outside = 6.2831853071run {val inside = 1.61803398875// outside和inside变量在此域范围能使用}// 只有outside能在此域范围使用}
‘this’ is the receiver
针对 scope functions 中的 apply run with , 已个很重要的功能就是 在代码块中被 this 引用的对象是一个被用在调用中的变量(the object referred to by this inside the block is the variable that’s used in the call)
class Foo {
//...
myView.run {
// this是myView的引用,而不是 Foo对象引用
alpha = 0.5f
background = ContextCompat.getDrawable(context, R.drawable.my_drawable)
}
}
因为 this 的 scope(域范围)已经变成了 run 代码块中的 myView ,如果想获取改变前的 this 对象,可以通过 this@Foo 去获取
Three, .. Two values
既然 scope functions 是 functions, 就应该有返回值, 可能的返回值如下:
The object itself
The last value of the block
N̶o̶t̶h̶i̶n̶g̶
apply
value第一种情况就是返回对象, 也就是receiver自己, 跟buidler很像. apply就是这样工作.
val paint = Paint().apply {
color = Color.MAGENTA
style = Paint.Style.STROKE
textSize = textHeadlinePx
}
run/with
第二种情况就是 function 类型, 返回值为代码块的最后一个表达式, 也就是run and with工作机制.
val line = PoetryGenerator.obtain().run {
style = "Emily Dickinson"
style += "Lucille Clifton"
lines = 1
generate()
}
line等于 generate() 此方法的返回值,如果假设返回可为null的话,返回值为this?.generate(), 然而的大部分使用方式都是如下:
with (myConfig) { //用于myConfig的配置,而不关心返回值
data = value
autoRefresh = false
// ...etc...
}
I’d rather be ‘it’
在很多情况下将 this 临时转换成其他对象引用挺方便,但是如下情况去显示很奇怪:
myIntent?.run {
data = this@MainActivity.data
startActivity(this)
}
this 在代码块中是 myIntent的引用,因此 startActivity(this) 看起来挺奇怪的,更舒服的方式应该是 startActivity(intent).
因此引入了 let 和 also scope function, 在此场景中,我们实质上想检查 myIntent 不为null时执行代码块中逻辑. Kotlin中针对此场景一贯的处理方式是用let scope function:
myIntent?.let {
it.data = data
startActivity(it)
}
let 和 run 的作用相同,除了对象被 this 引用改成了被 it 引用
完整的写法如下:
myIntent?.let { intent ->
intent.data = data
startActivity(intent)
}
also 的作用方式和 apply 相似,也只是对象被 this 引用改成了被 it 引用
also 很实用有两个主要的原因:
- it 可以被认为用做其名字:创建一个对象并且用it操作
val myListener = Listener().also {
addListener(it)
}
- 当与不相关联的对象和表达式协作时,优势更加明显(可以在不改变原本代码的前提下实现功能)
val key: String get() = keystore.getKey(KEY_ID).also {
Log.v(TAG, "Read key at ${System.currentTimeMillis()}")
}
How do I choose?
如果想返回开始的对象, 选择 apply 和 also. 如果想返回方法中的值,选择 let, run, 和 with.

