作用域函数,就是些技巧性方法,函数定义全在Standard.kt文件里。本篇,用实例记录一下它们的用法。
1.所谓作用域函数:它们的lamda函数作用域===对象类内部作用域。 就像是对象类的内部方法一样。
这样在lamda函数内,可以直接调用对象的方法,属性,不需要通过对象实例点出方法,属性。
2. let/takeIf/takeLess, 需要it引导
3. with是独立函数,其他函数都可由对象点出来。
- run,利用操作对象的方法属性,完成一些工作。最后在函数体内返回指定值。
val list = listOf("apple", "orange", "pear")
val result = StringBuilder().run {
append("Start eating fruits.\n")
for (fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits.")
toString()
}
println(result)
- apply,用于修改对象自己。修改后,如果函数有接收返回,接收的也是修改后的自己。函数体类不需要返回对象。
fun main() {
val user = User("alan", 18)
val applyResult = user.apply {
//这儿都是user对象的作用域
age = 20
}
println(applyResult) //输出:User(name=Peter, age=20)
println(user) //输出:User(name=Peter, age=20)
println(applyResult === user) //输出:true
}
data class User(var name: String, var age: Int)
第二个例子:
val list = listOf("apple", "orange", "pear")
val result = StringBuilder().apply{
append("Start eating fruits.\n")
for (fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits.")
}
println(result.toString())
- with,作用和run一样。不同的是,run由对象点出,而with是独立的函数,对象是作为with的参数。
val list = listOf("apple", "orange", "pear")
val result = with(StringBuilder()) {
append("Start eating fruits.\n")
for (fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits.")
toString()
}
println(result)
- let, 把原始对象作为lamda表达式的参数,传入函数体。通常用来简化判空操作, 而且是线程安全的。
object.let{
it.todo()//在函数体内使用it替代object对象去访问其公有的属性和方法
...
}
//另一种用途 判断object为null的操作
object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo()
}
?下面的写法,有点罗嗦,如果使用user的参数方法更多,就要被问号烦死了。
fun doStudy(user:User?){
user?.age = 20
user?.name = "alan"
}
或者用if判空:
fun doStudy(user:User?){
if(user != null){
user.age = 20
user.name = "alan"
}
}
用let函数简化:
fun doStudy(user:User?){
user?.let{
it.age = 20
it.name = "alan"
}
针对if判空那种方式,是有问题的。当User对象是全局对象的时候。就编译错误了。提示有多线程问题。
var user:User? = null
fun doStudy() {
if (user!=null) {
user.age = 20 //编译错误提醒
user.name = "alan"//编译错误提醒
}
}
- also, 和let的作用一样。不同点就是,let函数的返回值是最后一行的返回值,而also函数的返回值是返回上下文对象本身。可以理解为"并且为该对象执行以下操作"。
一般可用于多个扩展函数链式调用。
fun main() {
val user = User("alan", 18)
val alsoResult = user.also {
println("user 之前的名字是:${it.name}") //user 之前的名字是:alan
}.apply {
name = "lin"
}
println(alsoResult) //User(name=lin, age=18)
println(user) //User(name=lin, age=18)
println(alsoResult === user) //true
}
data class User(var name: String, var age: Int)
- takeIf,takeunless,?前面调用了一个函数计算得出了一个结果,现在需要对这个结果做一个分支判断,并且我们只需要用到if的一个分支时,可以用takeIf和takeUnless代替。
takeIf,takeunless,?区别就只有一个是满足代码块里面的条件才返回对象本身,一个是不满足条件才返回。
下面三段代码都是等价的:
用if语句:
fun testWithoutTakeIf() {
val name = "alan Gong"
val hasGong = name.indexOf("Gong")
Log.i(TAG, "testWithoutTakeIf: hasGong = $hasGong")
if (hasGong >= 0) {
Log.i(TAG, "testWithoutTakeIf: has Gong")
}
Log.i(TAG, "testWithoutTakeIf: $name")
}
输出:
I: testWithoutTakeIf: hasGong = 0
I: testWithoutTakeIf: has Gong
I: testWithoutTakeIf: alan Gong
用takeIf:
fun testTakeIf() {
val name = "alan Gong"
name.indexOf("Gong")
.takeIf {
Log.i(TAG, "testTakeIf: it = $it")
it >= 0
}
?.let {
Log.i(TAG, "testTakeIf: has Gong")
}
Log.i(TAG, "testTakeIf: $name")
}
输出:
I: testTakeIf: it = 0
I: testTakeIf: has Gong
I: testTakeIf: alan Gong
用takeLess: 注意函数体的判断和takeIf函数体里相反。
fun testTakeUnless() {
val name = "alan Gong"
name.indexOf("Gong")
.takeUnless {
Log.i(TAG, "testTakeUnless: it = $it")
it < 0
}
?.let {
Log.i(TAG, "testTakeUnless: has Gong")
}
Log.i(TAG, "testTakeUnless: $name")
}
输出:
I: testTakeUnless: it = 0
I: testTakeUnless: has Gong
I: testTakeUnless: alan Gong
由上面的简单例子也可以看出,这两个通常和其他作用域函数,组成链式调用。
repeat(3){
println("repeat")
}
好了,目前所有的作用域函数都记录清楚了。看起来是挺强大的,但是这种东西多了,可读性就不见得好了。另外还有一张网络上的总结图:
|