作用域函数
在kotlin的标准库里,提供了一些目的在于以对象为上下文执行代码块的函数,这些函数叫做作用域函数,在作用域函数内,可以访问不带名称的对象,可以在一个对象中使用lambda
表达式调用这些函数。作用域函数包括let
、run
、with
、apply
、also
。
示例:
fun main(args: Array<String>) {
val p = Persion("aaaa", 20)
println(p)
p.let {
it.grow()
it.changeName("bbbb")
}
print(p)
}
class Persion(var name: String, var age: Int) {
fun grow() {
age++
}
fun changeName(newName: String) {
name = newName
}
override fun toString(): String {
return "Persion(name='$name', age=$age)"
}
}
上面的例子中,使用了
let
作用域函数,在作用域内,无需对象名称就可以调用对象并修改相应的属性
区别
作用域函数有相似的性质,需要清楚他们之间的区别,才能更好的使用。作用域函数的区别主要有两个:
- 引用上下文对象的方式
- 返回值
引用上下文对象的方式:this
还是it
在作用域函数的lambda
表达式中,上下文对象可通过短引用, 而不是其实际名称来使用。每个作用域函数使用两种访问上下文对象的方式之一:作为lambda
接收器(this
)或作为lambda
参数(it
)。两者都提供相同的功能,因此我们将描述每种情况在每种情况下的利弊,并提供有关其用法的建议。
// it 作为lambda表达式的参数
p.let {
// 使用时,需要使用it作为引用
it.grow()
it.changeName("bbbb")
}
// this 作为lambda表达式的接收者
p.run {
// 使用时,可以认为是在对象内部调用,不需要显式this引用
grow()
changeName("bbbb")
}
this
run
、with
和apply
这三个作用域函数使用this
应用上下文,this
作为lambda
表达式的接收者。在lambda
的内部,可以像在类内部那样调用对象的函数及访问属性,在大多数情况下,this
可以省略(不显式调用),但是如果省略this
,将无法区分在lambda
表达式中调用的上下文对象的成员,还是外部的方法或者属性(尤其上下文对象的成员函数或者属性与外部同名是,一定不能忽略this
)。
it
let
和also
这两个作用域函数使用it
上下文对象作为lambda
表达式的参数(如果未指定lambda
表达式的参数名称,默认是it
),在调用上下文对象的函数及属性时,it
作为一个参数,所以必须显式调用不能忽略。
// it 作为lambda表达式的参数
p.let {
// 使用时,需要使用it作为引用,不可忽略
it.grow()
it.changeName("bbbb")
}
p.let { person -> // 可以指定参数名称
// 使用时,需要使用it作为引用,不可忽略
person.grow()
person.changeName("cccc")
}
作用域函数的返回值
作用域函数之中一个不同之处在于它们返回的结果,不同的返回值也可以作为在代码中选用哪一种作用域函数的标准之一:
apply
并also
返回上下文对象。let
,run
和with
返回lambda
表达式的结果。
返回上下文对象
apply
并also
返回上下文对象,返回上下文对象的好处就是,可以在作用域函数之后的代码中继续使用.
运算符执行其他调用
p.apply {
grow()
changeName("bbbb")
}.let {
it.grow()
it.changeName("bbbb")
}
返回lambda
表达式结果
let
,run
和with
返回lambda
表达式的结果,可以实现在代码中获取作用域函数内的计算结果。
// result的值为lambda表达式的结果,执行完作用域函数代码块后,result获得表达式的结果年龄值
val result = p.let {
it.grow()
it.changeName("bbbb")
it.age
}