用小明的故事随便谈谈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 结果 |
apply
函数接收一个 lambda 表达式作为参数,并返回被调用对象本身。通过apply
,可以在对象创建后立即对其进行链式操作,设置属性值、调用方法等。适合用于链式初始化或配置一些属性。
val person = Person().apply {
name = "John"
age = 30
}
also
函数接收一个 lambda 表达式作为参数,lambda 表达式中的 it 引用指向调用also
的对象。通过also
,可以对对象进行额外的操作,而原对象仍然是函数调用的结果。适合用于在对象操作过程中执行额外的副作用操作。
val modifiedObject = myObject.also {
// 额外操作 it
}
let
函数接收一个 lambda 表达式作为参数,lambda 表达式中的 it 引用指向调用let
的对象。如果对象不为空,则执行 lambda 表达式内的操作,并返回 lambda 表达式的结果。适合用于安全地操作对象,避免空指针异常。
val result = nullableValue?.let {
// 操作非空对象 it
}
run
函数接收一个 lambda 表达式作为参数,lambda 表达式中的 this 引用指向调用run
的对象。通过run
,可以便捷地对对象进行多次操作,并返回最后一个表达式的结果。适合用于执行一系列操作并返回最终结果。
val result = myObject.run {
// 对象操作1
// 对象操作2
// ...
// 返回结果
}
with
函数接收一个对象和一个 lambda 表达式作为参数,lambda 表达式中的 this 引用指向传入的对象。通过with
,可以在没有对象接收者的情况下操作对象,并返回最后一个表达式的结果。适合用于对对象进行一系列操作,而无需在乎返回值。
val result = with(myObject) {
// 对象操作1
// 对象操作2
// ...
// 返回结果
}
小明的故事
故事是这样的
- 小明今年上一年级
- 但是家长跟学校说,小明是个天才,现在可以直接跳级到二年级
- 学校给二年级分配的老师是王老师,是个女教师
- 半学期后,王老师怀孕了需要休息,于是学校给王老师放假
- 学校给二年级分配了新的李老师,小明有了新老师
下面是故事的代码:
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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://juejin.cn/post/7255795059660193850
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。