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