Kotlin的Standard.kt中的一些函数很相像,很多时候我们不确定使用哪个。这篇文章我将教大家如何区分他们的不同,以及如何在正确的场景下使用正确的函数
Standard.kt中有 run,T.run,with,T.apply,T.also,T.let几个函数,他们的共同的功能都是执行程序。但是他们之间还是有区别的。
一共有6个函数。我将根据返回值以及block函数的参数对它归类
T.apply和T.also是一对,它们的返回值为this,他们的区别在于apply block参数中传递的是this,also block参数中传递的是it
T.run和T.let是一对,它们的返回值是block执行的结果,它们的区别在于run block参数传递的是this,let block参数传递的是it
run和with是一对,run block参数中既不是this也不是it。with block参数是this
函数块
首先我们用run函数来演示下函数块
fun test() { var mood = "I am sad" run { val mood = "I am happy" println(mood) // I am happy } println(mood) // I am sad }
在函数块中我们可以重新声明mood变量
with和T.run对比
with(webview.settings) { javaScriptEnabled = true databaseEnabled = true } // similarly webview.settings.run { javaScriptEnabled = true databaseEnabled = true }
他们两实现的功能是一样的。如果webview.setting可能为null
// Yack! with(webview.settings) { this?.javaScriptEnabled = true this?.databaseEnabled = true } } // Nice. webview.settings?.run { javaScriptEnabled = true databaseEnabled = true }
this vs it参数
stringVariable?.run { println("The length of this String is $length") } // Similarly. stringVariable?.let { println("The length of this String is ${it.length}") }
如果你检查T.run函数签名,你会发现T.run它只是作为扩展函数调用block: T.()。因此,在范围内,T可以称为this。在编程中,this大多数时候可以省略。因此,在上面的示例中,我们可以l e n g t h 在 p r i n t l n 语 句 中 使 用 , 而 不 是 length在println语句中使用,而不是length在println语句中使用,而不是{this.length}。我称之为发送此作为参数。
返回this vs 返回other
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}") }
他们微妙的不同就是他们的返回值。T.let返回的是函数快的返回值Unit,而T.also返回T本身即this
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 }
他们微妙的不同就是他们的返回值。T.let返回的是函数快的返回值Unit,而T.also返回T本身即this
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 }
使用
// 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() }
// 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) }