一:概念
Kotlin 标准库包含几个函数,它们的唯一目的是在对象的上下文中执行代码块。当对一个对象调用这样的函数并提供一个 lambda 表达式时,它会形成一个临时作用域。在此作用域中,可以访问该对象而无需其名称。这些函数称为作用域函数。共有以下五种:let
、run
、with
、apply
以及 also
。
这些函数基本上做了同样的事情:在一个对象上执行一个代码块。不同的是这个对象在块中如何使用,以及整个表达式的结果是什么。
先来看下如果不用作用域函数,我们平常是怎么在进行处理代码的。
val alice = PersonMen("Alice", 20, "Amsterdam")
alice.age=16
alice.gj="Ydl"
通过作用域函数let看下是怎么调用的:
PersonMen("Alice", 20, "Amsterdam").let {
it.age=30
it.gj="London"
}
可见使用了let函数,形成一个临时的作用域。在此作用域中,可以访问该对象而无需其名称。
二:5个作用域函数的区别和相处
以下的表格是对五个作用域函数的对比
作用域函数 | 上下文对象 | 返回结果类型 | 是否能单独使用 |
---|---|---|---|
let | it(可自定义) | lambda表达式的最后一行是返回值 | 否 |
also | it(可自定义) | T的类型(上下文对象) | 否 |
run | this(可隐式地访问对象) | lambda表达式的最后一行是返回值 | 否 |
apply | this(可隐式地访问对象) | T的类型(上下文对象) | 否 |
with | this(可隐式地访问对象) | lambda表达式的最后一行是返回值 | 是 |
1:上下文对象
var str: String= "Hello"
str.let {
println("let() called on $it")
}
str.also {
println("also() called on $it")
}
str.run {
println("run() called on $this")
}
str.apply {
println("apply() called on $this")
}
with(str) {
println("with() called on $this")
}
输出结果
let() called on Hello
also() called on Hello
run() called on Hello
apply() called on Hello
with() called on Hello
- this可隐式地访问对象,it不能
str.let {
it.length
}
str.run {
this.length
length
}
从以上代码可知,this省略也可以直接调用length,但是如果it省略直接写 length ,代码是会报错
- it作为上下文可进行自定义这个上下文的名字
str.let {value->
value.length
}
代码中定义value为上下文,但是this则不可以
2:返回结果类型
var list: MutableList<String> = mutableListOf<String>()
list.add("b")
var letResult = list.let {
it.add("a")
}
println("let() called on $letResult")
println("let() called on $list")
结果:
let() called on true
let() called on [b, a]
可以看出let函数返回结果是:lambda表达式的最后一行的值
换成also函数:
var list: MutableList<String> = mutableListOf<String>()
list.add("b")
var letResult = list.also {
it.add("a")
}
println("also() called on $letResult")
println("also() called on $list")
输出结果:
also() called on [b, a]
also() called on [b, a]
可以看出also函数返回结果是:T的类型(上下文对象)
3.是否能单独使用
这个在我的理解是是否一定要跟在"."的后面,这样就限制了函数的使用位置,五种函数中不同的是with函数,with
可以理解为“对于这个对象,执行以下操作。”
with(str) {
println("with() called on $this")
}
三:函数选择
以下是根据预期目的选择作用域函数的简短指南:
- 对一个非空(non-null)对象执行 lambda 表达式:
let
- 将表达式作为变量引入为局部作用域中:
let
- 对象配置:
apply
- 对象配置并且计算结果:
run
- 在需要表达式的地方运行语句:非扩展的
run
- 附加效果:
also
- 一个对象的一组函数调用:
with
不同函数的使用场景存在重叠,你可以根据项目或团队中使用的特定约定选择函数。
尽管作用域函数是使代码更简洁的一种方法,但请避免过度使用它们:这会降低代码的可读性并可能导致错误。避免嵌套作用域函数,同时链式调用它们时要小心:此时很容易对当前上下文对象及 this
或 it
的值感到困惑。