Kotlin的run、let、also和apply的用法
公司的Web框架逐渐换成了自研的Kotlin框架,臃肿的Java代码得到极大的改善。在Kotlin世界里面,脚本式的运行环境很容易导致局部变量被污染,所以Kotlin内置了很多局部函数来辅助。
run
fun test() {
var mood = "I am sad"
run {
val mood = "I am happy"
println(mood) // I am happy
}
println(mood) // I am sad
}
run提供了一个闭包,使得内部变量可以与外部变量不产生命名冲突。
run {
if (firstTimeView) introView else normalView //动态决定不同View
}.show()
run支持返回最后一个表达式的值,利用这个特性可以在run里面完成类似动态选择的功能。
with
webview.settings.javaScriptEnabled = true
webview.settings.databaseEnabled = true
//使用with,上面代码可以简化成下面样式
with(webview.settings) {
javaScriptEnabled = true
databaseEnabled = true
}
with提供了一个隐藏对象,从而简化了对这个对象处理的臃肿代码。
其实run也支持类似with的功能:
webview.settings.run{
javaScriptEnabled = true
databaseEnabled = true
}
既然with和run都有类似的功能,在什么情况下需要选择run呢?
//丑
with(webview.settings) {
this?.javaScriptEnabled = true
this?.databaseEnabled = true
}
//爽
webview.settings?.run {
javaScriptEnabled = true
databaseEnabled = true
}
面对not-null的情况,object?.run{ }
用起来会比with好用很多。实际项目里面,run的使用频率也是更高的。
run vs let
run和let在大部分时候用途都是非常接近的,例如下面例子:
user?.run{
//user ==> this
println("my name is $name)
}
user?.let{
//user ==> it
println("my name is $it.name")
}
虽然看起来没啥特别大的区别,let实际上提供了更好语义说明语法,例如下面:
loginedUser.id?.let {
userId ->
User.findById(userId)
}
loginedUser.id?.run {
User.findById(this) //this指的是啥?不仔细琢磨还看不出来
}
let vs also
let和also在使用方面,非常像,对象都是默认简化成it
:
stringVariable?.let {
println("The length of this String is ${it.length}")
}
// Exactly the same as below
stringVariable?.also {
println("The length of this String is ${it.length}")
}
let和also真正的区别在于返回值不同:
val original = "abc"
original.let{
println(it) //abc
it.reversed()
}.let{
println(it) //cba
}
original.also{
println(it) //abc
it.reversed()
}.also{
println(it) //abc
}
let每次会返回最后一个表达式的结果,而also会返回内置对象。
let和also经常会搭配一起使用,例如下面:
//java逻辑应该是写成这样子的
fun makeDir(path: String): File {
val result = File(path)
result.mkdirs()
return result
}
//在kotlin里面,使用let和also可以简写
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }
apply
apply的作用如下:
obj.run{
name = "hello"
this
}
//以上的代码,可以简写为下面
obj.apply{
name = "hello"
}
其实就是在run最后一行强行塞入this。
下面看看实战作用:
//java逻辑应该是写成这样子的
fun createIntent(intentData: String, intentAction: String): Intent {
val intent = Intent()
intent.action = intentAction
intent.data=Uri.parse(intentData)
return intent
}
//在kotlin里面,使用apply可以简写
fun createIntent(intentData: String, intentAction: String) =
Intent().apply { action = intentAction }
.apply { data = Uri.parse(intentData) }
总结
不管是run、with、also还是apply,最终的目的还是提供了一个简化代码的语法糖。老实说,相比起java,理解起来费劲很多很多。