提供了一个 内部独立的区间(也就是方法的上下文 如下的run方法)
T.
就是T相当于方法内部(作用域内)的thisT
就是T相当于lambda的参数fun test() {
var mood = "I am sad"
run {
val mood = "I am happy"
println(mood) // I am happy
}
println(mood) // I am sad
}
run {
if (firstTimeView) introView else normalView
}.show()
从这三个属性的维度 来对上述方法,再次划分
1. Normal vs. extension function
//normal function
with(webview.settings) {
javaScriptEnabled = true
databaseEnabled = true
}
// similarly function
// extension function
webview.settings.run {
javaScriptEnabled = true
databaseEnabled = true
}
好处 webview.settings 可能为null,所以安全的写法:
// Yack!
with(webview.settings) {
this?.javaScriptEnabled = true
this?.databaseEnabled = true
}
}
// Nice.
webview.settings?.run {
javaScriptEnabled = true
databaseEnabled = true
}
T.run和T.let只有一点不同 他们接受的参数
stringVariable?.run {
println("The length of this String is $length")
}
// Similarly.
stringVariable?.let {
println("The length of this String is ${it.length}")
}
看方法的signature(方法签名,包括方法参数列表),发现T.run是一个扩展方法block: T.() 所以在scope内T是被当做this,方法中this可以被省略,所以$length
等价于${this.length}
T.let方法的signature是block: (T)
像lambda表达式一样,这里我们成为 it 参数
另外it也是可以改名的:
stringVariable?.let {
nonNullString ->
println("The non null string is $nonNullString")
}
T.let and T.also
val original = "abc"
// Evolve the value and send to the next chain
original.let {
println("The original String is $it") // "abc"
it.reversed() // evolve it as parameter to send to next let
}.let {
println("The reverse String is $it") // "cba"
it.length // can be evolve to other type
}.let {
println("The length of the String is $it") // 3
}
// Wrong
// Same value is sent in the chain (printed answer is wrong)
original.also {
println("The original String is $it") // "abc"
it.reversed() // even if we evolve it, it is useless
}.also {
println("The reverse String is ${it}") // "abc"
it.length // even if we evolve it, it is useless
}.also {
println("The length of the String is ${it}") // "abc"
}
// Corrected for also (i.e. manipulate as original string
// Same value is sent in the chain
original.also {
println("The original String is $it") // "abc"
}.also {
println("The reverse String is ${it.reversed()}") // "cba"
}.also {
println("The length of the String is ${it.length}") // 3
}
let return的是这次调用的结果,also return的仍旧是调用方
also看起来没用,可以整合到一个方法,但是也有好处:
1. It can provide a very clear separation process on the same objects i.e. making smaller functional section. (更细粒度的分割代码、逻辑)
2. It can be very powerful for self manipulation before being used, making a chaining builder operation.(有利于build模式)
// Normal approach
fun makeDir(path: String): File {
val result = File(path)
result.mkdirs()
return result
}
// Improved approach
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }
上面说的this实际就是T
// Normal approach
fun createInstance(args: Bundle) : MyFragment {
val fragment = MyFragment()
fragment.arguments = args
return fragment
}
// Improved approach
fun createInstance(args: Bundle)
= MyFragment().apply { arguments = args }
非链式的做成链式调用
// Normal approach
fun createIntent(intentData: String, intentAction: String): Intent {
val intent = Intent()
intent.action = intentAction
intent.data=Uri.parse(intentData)
return intent
}
// Improved approach, chaining
fun createIntent(intentData: String, intentAction: String) =
Intent().apply { action = intentAction }
.apply { data = Uri.parse(intentData) }
原文: Mastering Kotlin standard functions: run, with, let, also and apply