Kotlin标准函数run with let also apply的区别

简介: Kotlin标准函数run with let also apply的区别

Kotlin的Standard.kt中的一些函数很相像,很多时候我们不确定使用哪个。这篇文章我将教大家如何区分他们的不同,以及如何在正确的场景下使用正确的函数

1_9nUzj5iRxj_Hddni6ob28w.pngStandard.kt中有 run,T.run,with,T.apply,T.also,T.let几个函数,他们的共同的功能都是执行程序。但是他们之间还是有区别的。


一共有6个函数。我将根据返回值以及block函数的参数对它归类

1_pLNnrvgvmG6Mdi0Yw3mdPQ.png


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) }



相关文章
|
12月前
|
Kotlin
kotlin 使用let与run结合,等价于if 与else
Kotlin 中?.let{}?:run{} 等价于 if{}else{}
344 1
|
编译器 Android开发 开发者
Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
Lambda表达式和匿名函数都是Kotlin中强大的特性,帮助开发者编写简洁而高效的代码。理解它们的区别和适用场景,有助于选择最合适的方式来解决问题。希望本文的详细讲解和示例能够帮助你在Kotlin开发中更好地运用这些特性。
359 9
|
IDE 开发工具 Kotlin
Kotlin - 函数与Lambda表达式
Kotlin - 函数与Lambda表达式
139 13
|
安全 Kotlin
Kotlin教程笔记(23) -作用域函数
Kotlin教程笔记(23) -作用域函数
255 6
|
Kotlin
Kotlin教程笔记(21) -高阶函数与函数引用
Kotlin教程笔记(21) -高阶函数与函数引用
144 6
|
IDE 开发工具 Kotlin
Kotlin教程笔记(6) - 函数与Lambda表达式
Kotlin教程笔记(6) - 函数与Lambda表达式
152 1
|
8月前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
386 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
430 1
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
**Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**
717 5
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
507 1