scope functions
Kotlin “scope functions” 允许改变一个变量的 scope,或者 range (作用域范围). 在此在Kotlin standard library中有五个类似方法: apply
, run
, with
, let
和 also
已 run
为例说明:
fun myFun() {
val outside = 6.2831853071
run {
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
.