• 一起来学Kotlin:概念:16. Kotlin Scope Function 作用域函数:let,run,with,apply,also


    一起来学Kotlin:概念:16. Kotlin Scope Function 作用域函数:let,run,with,apply,also

    这里我们将介绍 Kotlin 5个作用域函数:let,run,with,apply,also。



    1 let

    let 可用于范围界定和空值检查。在对象上调用时,let 执行给定的代码块并返回其最后一个表达式的结果。对象可通过引用它(默认情况下)或自定义名称在块内进行访问。

    所以,总结起来,let 有如下三大特征:

    // 重点11:使用it替代object对象去访问其公有的属性 & 方法
    object.let{
       it.todo()
    }
    
    // 重点2:判断object为null的操作
    object?.let{//表示object不为null的条件下,才会去执行let函数体
       it.todo()
    }
    
    // 重点3:返回值 = 最后一行 / return的表达式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    下面是一些例子(我们可以直接在 Kotlin Playground 中运行):

    fun customPrint(s: String) {
        print(s.uppercase())
    }
    
    fun main() {
        val empty = "test".let {               // Calls the given block on the result on the string "test".
            customPrint(it)                    // 这里的 it 就是 "test",所以 "test" 作为输入给到 customPrint 函数中,打印出大写的 "test"
            it.isEmpty()                       // let 最后返回的是这个,也就是 empty 最终的值是 false
        }
        println(" is empty: $empty")           // 打印结果 TEST is empty: false。这里的 TEST 是 customPrint 函数 的打印结果。注意 print 和 println 的区别
    
    
        fun printNonNull(str: String?) {
            println("Printing \"$str\":")
    
            str?.let {                         // object不为null的条件下,才会去执行let函数体
                print("\t")
                customPrint(it)
                println()                      // 换行。let最后返回的是这一行
            }
        }
    
        fun printIfBothNonNull(strOne: String?, strTwo: String?) {
            strOne?.let { firstString ->       
                strTwo?.let { secondString ->
                    customPrint("$firstString : $secondString")
                    println()
                }
            }
        }
    
        printNonNull(null)                    // 打印 Printing "null":
        printNonNull("my string")             // 打印 Printing "my string":
    	                                             // MY STRING
        printIfBothNonNull("First","Second")  // 打印 FIRST : SECOND
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    从另一个方面,我们来比对一下不使用 let 和使用 let 函数的区别。

    // 使用kotlin(无使用let函数)
    mVar?.function1()
    mVar?.function2()
    mVar?.function3()
    
    // 使用kotlin(使用let函数)
    // 方便了统一判空的处理 & 确定了mVar变量的作用域
    mVar?.let {
           it.function1()
           it.function2()
           it.function3()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2 run

    与 let 函数类似,run 函数也返回最后一条语句。另一方面,与 let 不同,运行函数不支持 it 关键字。所以,run 的作用可以是:

    • 调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可
    • 定义一个变量在特定作用域内
    • 统一做判空处理

    下面是一些例子:

    fun main() {
        fun getNullableLength(ns: String?) {
            println("for \"$ns\":")
            ns?.run {                                                  // 判空处理
                println("\tis empty? " + isEmpty())                    // 这里我们就发现,在 isEmpty 前不再需要 it
                println("\tlength = $length")                           
                length                                                 // run returns the length of the given String if it's not null.
            }
        }
        getNullableLength(null)   
        // 打印 for "null":
        getNullableLength("")
        // 打印 for "":
        //         is empty? true
        //         length = 0
        getNullableLength("some string with Kotlin")
        // 打印 for "some string with Kotlin":
        //         is empty? false
        //         length = 23
    
        data class People(val name: String, val age: Int) 
        val people = People("carson", 25)
        people?.run{
          println("my name is $name, I am $age years old")
          // 打印:my name is carson, I am 25 years old
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    3 with

    with 是一个非扩展函数,可以简洁地访问其参数的成员:我们可以在引用其成员时省略实例名称。所以说,run 相当于 let 和 with 的集合。

    class Configuration(var host: String, var port: Int) 
    
    fun main() {
        val configuration = Configuration(host = "127.0.0.1", port = 9000) 
    
        with(configuration) {
            println("$host:$port")   // 打印 127.0.0.1:9000
        }
    
        // instead of:
        println("${configuration.host}:${configuration.port}")    // 打印 127.0.0.1:9000
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4 apply

    apply 对对象执行代码块并返回对象本身。在块内部,对象由此引用。此函数对于初始化对象非常方便。所以再重复一遍,apply函数返回传入的对象的本身。

    data class Person(var name: String, var age: Int, var about: String) {
        constructor() : this("", 0, "")
    }
    
    fun main() {
        val jake = Person()                   
        val stringDescription = jake.apply {  
            // Applies the code block (next 3 lines) to the instance.
            name = "Jake"                                   
            age = 30
            about = "Android developer"
        }.toString()                            
        println(stringDescription)      // 打印 Person(name=Jake, age=30, about=Android developer)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5 also

    类似 let 函数,但区别在于返回值:

    • let 函数:返回值 = 最后一行 / return的表达式
    • also 函数:返回值 = 传入的对象的本身
    // let函数
    var result = mVar.let {
                   it.function1()
                   it.function2()
                   it.function3()
                   999
    }
    // 最终结果 = 返回999给变量result
    
    // also函数
    var result = mVar.also {
                   it.function1()
                   it.function2()
                   it.function3()
                   999
    }
    // 最终结果 = 返回一个mVar对象给变量result
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    另一个类似的例子:

    data class Person(var name: String, var age: Int, var about: String) {
                 constructor() : this("", 0, "")
    }
             
    fun writeCreationLog(p: Person) {
        println("A new person ${p.name} was created.")              
    }
             
    fun main() {
        val jake = Person("Jake", 30, "Android developer")   // 1
            .also {                                          // 2 
                writeCreationLog(it)                         // 3
            }
        println(jake)   
        // 最终打印:
        // A new person Jake was created.
        // Person(name=Jake, age=30, about=Android developer)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    vscode连接服务器步骤
    KT142C-sop16语音芯片的4个IO口如何一对一触发播放_配置文件详细说明
    多项分布模拟及 Seaborn 可视化教程
    Centos 7安装ansible自动化运维工具
    【JavaEE初阶】 TCP三次握手四次挥手(超详细版)
    IDEA远程断点调试jar包项目
    7-9 HashSet 重写相应方法
    SpringBoot几个常用的注解
    介绍 CI / CD
    ngxin开发一个静态http服务器二
  • 原文地址:https://blog.csdn.net/zyctimes/article/details/127814513