用小明的故事随便谈谈kotlin中的apply等函数

前言

本文仅简单描述一下kotlin中常用到的scope function,如apply,let,run,with,also等函数的常用方法和选取。即使很多情况下选择不同函数,也同样都能达到最终效果,具体选择哪个函数我们不会严格约束,但如果你是对代码规范要求比较高的,最好建立良好的代码习惯。

一般对比

函数一般使用场景函数定义上下文对象可用作返回值
apply在需要对对象进行初始化或配置的时候使用public inline fun <T> T.apply(block: T.() -> Unit): T接收器this返回值是对象本身
also在需要对对象执行额外操作并返回原对象的时候使用public inline fun <T> T.also(block: (T) -> Unit): T变量it返回值是对象本身
let在需要对对象进行非空判断并执行特定操作的时候使用public inline fun <T, R> T.let(block: (T) -> R): R变量it返回值是 lambda 结果
run在需要对对象进行多个操作,并返回一个结果的时候使用,通常是一个新的对象或其他public inline fun <T, R> T.run(block: () -> R): R 接收器this返回值是 lambda 结果
with在不拥有对象的上下文的时候使用public inline fun <T, R> with(receiver: T, block: T.() -> R): R接收器this返回值是 lambda 结果
  1. apply 函数接收一个 lambda 表达式作为参数,并返回被调用对象本身。通过 apply,可以在对象创建后立即对其进行链式操作,设置属性值、调用方法等。适合用于链式初始化或配置一些属性。
val person = Person().apply { 
        name = "John" 
        age = 30 
    }
  1. also 函数接收一个 lambda 表达式作为参数,lambda 表达式中的 it 引用指向调用 also 的对象。通过 also,可以对对象进行额外的操作,而原对象仍然是函数调用的结果。适合用于在对象操作过程中执行额外的副作用操作。
val modifiedObject = myObject.also {
    // 额外操作 it
}
  1. let 函数接收一个 lambda 表达式作为参数,lambda 表达式中的 it 引用指向调用 let 的对象。如果对象不为空,则执行 lambda 表达式内的操作,并返回 lambda 表达式的结果。适合用于安全地操作对象,避免空指针异常。
val result = nullableValue?.let {
    // 操作非空对象 it
}
  1. run 函数接收一个 lambda 表达式作为参数,lambda 表达式中的 this 引用指向调用 run 的对象。通过 run,可以便捷地对对象进行多次操作,并返回最后一个表达式的结果。适合用于执行一系列操作并返回最终结果。
val result = myObject.run {
    // 对象操作1
    // 对象操作2
    // ...
    // 返回结果
}

  1. with 函数接收一个对象和一个 lambda 表达式作为参数,lambda 表达式中的 this 引用指向传入的对象。通过 with,可以在没有对象接收者的情况下操作对象,并返回最后一个表达式的结果。适合用于对对象进行一系列操作,而无需在乎返回值。
val result = with(myObject) {
    // 对象操作1
    // 对象操作2
    // ...
    // 返回结果
}

小明的故事

故事是这样的

  1. 小明今年上一年级
  2. 但是家长跟学校说,小明是个天才,现在可以直接跳级到二年级
  3. 学校给二年级分配的老师是王老师,是个女教师
  4. 半学期后,王老师怀孕了需要休息,于是学校给王老师放假
  5. 学校给二年级分配了新的李老师,小明有了新老师

下面是故事的代码:


data class Student(var name: String = "", var grade: String = "", var teacher: Teacher? = null) {
    //插班跳级
    fun needSkippingGrade(insertGrade: String) {
        this.grade = insertGrade
    }
}

data class Teacher(var name: String = "") {
    fun relax() {
        println("$name 休假了!")
    }
}

fun main() {

    //1. **小明**今年上一年级
    val xiaoming = Student()
        .apply {
            name = "小明"
            grade = "一年级"
            println("小明开始前: $this")
        }
        .also {
            //2.现在可以直接跳级到二年级
            it.needSkippingGrade("二年级")
            println("小明插班后: $it")
        }

    //3. 学校给二年级分配的老师是**王老师**,是个女教师
    val ownTeacher = xiaoming.teacher?.let {
        println("小明当前的老师不为NULL,是${it}")
    } ?: Teacher("王老师").also {
        xiaoming.teacher = it
        println("小明有了老师: $xiaoming")
    }
    
    fun changeStudentCurrentTeacher(student: Student): Teacher? {
        return student.run {
            teacher?.relax()
            Teacher("李老师")
        }
    }

    //4. 半学期后,王老师怀孕了需要休息,于是学校给王老师放假
    //5. 学校给二年级分配了新的**李老师**,小明有了新老师
    with(xiaoming) {
        println("开学了!")
        println("半学期后,王老师怀孕了!...")
        val newTeacher = changeStudentCurrentTeacher(this)
        println("新老师是$newTeacher")
        teacher = newTeacher
        println("小明有了新老师$this")
    }

}

输出结果:

小明开始前: Student(name=小明, grade=一年级, teacher=null)
小明插班后: Student(name=小明, grade=二年级, teacher=null)
小明有了老师: Student(name=小明, grade=二年级, teacher=Teacher(name=王老师))
开学了!
半学期后,王老师怀孕了!...
王老师 休假了!
新老师是Teacher(name=李老师)
小明有了新老师Student(name=小明, grade=二年级, teacher=Teacher(name=李老师))

最后

实际过程中,需要根据具体的场景和需求来选择适合的函数。前面这些函数在 Kotlin 中提供了更简洁、可读性更高的方式来处理对象,根据不同的使用场景,你可以选择最适合和更易读的函数来操作对象。

全部评论

相关推荐

点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务