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,理解起来费劲很多很多。