前言

本文仅简单描述一下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 中提供了更简洁、可读性更高的方式来处理目标,依据不同的运用场景,你能够挑选最合适和更易读的函数来操作目标。