注册

用小明的故事随便谈谈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 中提供了更简洁、可读性更高的方式来处理对象,根据不同的使用场景,你可以选择最适合和更易读的函数来操作对象


作者:Kanvast
链接:https://juejin.cn/post/7255795059660193850
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册