五个作用域,会比较长。
这篇文章,类似于字典。查查。用用。
主要需要了解的点
① 有什么区别?
② 如何选择?
通过编译器的手段增加一些操作符,使代码变得更简洁
所以,你不用它也完全可以实现相同的功能。
它提供了一个临时作用域,让对象执行代码块的 代码看起来更简洁
data class Person(var name: String, var age: Int, var city: String) {
fun moveTo(newCity: String) { city = newCity }
fun incrementAge() { age++ }
}
fun main() {
Person("Alice", 20, "Amsterdam").let {
println(it)
it.moveTo("London")
it.incrementAge()
println(it)
}
}
我们将main()函数的代码改成普通的方式
val alice = Person("Alice", 20, "Amsterdam")
println(alice)
alice.moveTo("London")
alice.incrementAge()
println(alice)
使用 let 之后,代码更显层次,更方便的寻找 Person alice的作用域(有效范围)
显然代码整洁了
但是可读性却下降了。lambda过多就会导致修改起来很累。
要考虑到交接成本。后来者可能改不动你的代码
《kotlin - let,run,with,apply,also作用域函数的区别》
很多时候这5个范围函数是可以互换的
同一个逻辑可以用不同的范围函数来实现
接下来讲讲 常见的使用方法
上下文对象: it
返回结果: lambda结果
fun main() {
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)
}
重写部分使用了某变量的逻辑,显得更有代码结构层次感
fun main() {
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let {
println(it)
}
}
若代码块 仅包含一个it参数的单一函数
fun main() {
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let(::println)
}
搭配 ?. 进行非空判断
fun processNonNullString(str: String) {}
fun main() {
val str: String? = null
//processNonNullString(str) // compilation error: str can be null
val length = str?.let {
println("let() called on $it")
processNonNullString(it) // OK: 'it' is not null inside '?.let { }'
it.length
}
}
这里str为null,则let不会被执行。若str有值,则let代码块可以被执行
使用 it的名别 来提高代码可阅读性
fun main() {
val numbers = listOf("one", "two", "three", "four")
val modifiedFirstItem = numbers.first().let { firstItem ->
println("The first item of the list is '$firstItem'")
if (firstItem.length >= 5) firstItem else "!" + firstItem + "!"
}.toUpperCase()
println("First item after modifications: '$modifiedFirstItem'")
}
这里的firstItem即it的别名。从字面上可以更清楚的制度这里的it是什么
上下文对象: this
返回结果: lambda结果
with可以被解读为: 请用这个object做以下的事情
用numbers去打印log
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("'with' is called with argument $this")
println("It contains $size elements")
}
调用其functions
fun main() {
val numbers = mutableListOf("one", "two", "three")
val firstAndLast = with(numbers) {
"The first element is ${this.first()}," +
" the last element is ${last()}"
}
println(firstAndLast)
}
这里会输出
The first element is one, the last element is three
上下文对象: this
返回结果: lambda结果
val hexNumberRegex = run {
val digits = "0-9"
val hexDigits = "A-Fa-f"
val sign = "+-"
Regex("[$sign]?[$digits$hexDigits]+")
}
可以看到没有 context对象
这里范例返回的就是Regex
let用的是it,run用的是this
class Person(var name: String, var height: Int) {
fun signIn(): String = "$name has sign in"
fun getHeight(height: String): String = "Height = '$height'"
}
fun main() {
val alice = Person("Alice", 188)
val result = alice.run {
this.name = "$name the Student"
println(signIn() + " to port " + getHeight("$height"))
"alice clone1 success" //输出最后一行的结果
}
// the same code written with let() function:
val result2 = alice.let {
it.name = "${it.name} the Student"
println(it.signIn() + " to port " + it.getHeight("${it.height}"))
"alice clone2 success" //输出最后一行的结果
}
println(result)
println(result2)
}
输出结果呢
Alice the Student has sign in to port Height = '188'
Alice the Student the Student has sign in to port Height = '188'
alice clone1 success
alice clone2 success
上下文对象: this
返回结果: 上下文对象
使用apply的代码块没有返回值,主要是操作上的接收器对象的成员
主要用来进行对象配置
data class Person(var name: String, var age: Int = 0, var city: String = "")
fun main() {
val adam = Person("Adam").apply {
age = 32
city = "London"
}
}
上下文对象: it
返回结果: 上下文对象
这可以理解为 我也要做什么什么
定义为附加功能最合适
fun main() {
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")
}
针对单个对象的过滤功能
匹配则返回该对象,不匹配返回null
与takeIf相反
takeIf和takeUnless是过滤
返回的结果 是 原先的对象
这可以达到链式调用的效果!!!
takeIf和takeUnless可以和五个作用域函数 搭配使用
fun main() {
val number = 6
val evenOrNull = number.takeIf { it % 2 == 0 }
val oddOrNull = number.takeUnless { it % 2 == 0 }
println("even: $evenOrNull, odd: $oddOrNull")
val number2 = 7
val evenOrNull2 = number2.takeIf { it % 2 == 0 }
val oddOrNull2 = number2.takeUnless { it % 2 == 0 }
println("even: $evenOrNull2, odd: $oddOrNull2")
}
可以 看出来takeIf与takeUnless的结果可能是null
所以这里,你会用到 ?.操作符 进行判空