官方讲解:https://www.kotlincn.net/docs/reference/scope-functions.html
函数选择
功能 | 对象参考 | 返回值 | 是扩展功能 |
---|---|---|---|
let |
it |
Lambda结果 | 是 |
run |
this |
Lambda结果 | 是 |
run |
- | Lambda结果 | 否:没有上下文对象调用 |
with |
this |
Lambda结果 | 否:将上下文对象作为参数。 |
apply |
this |
上下文对象 | 是 |
also |
it |
上下文对象 | 是 |
以下是根据预期目的选择范围功能的简短指南:
- 在非null对象上执行lambda:
let
- 将表达式作为局部范围中的变量引入:
let
- 对象配置:
apply
- 对象配置和计算结果:
run
- 运行需要表达式的语句:非扩展名
run
- 附加效果:
also
- 对对象进行分组函数调用:
with
不同功能的用例重叠,因此您可以根据项目或团队中使用的特定约定选择功能。
虽然范围函数是使代码更简洁的一种方法,但是要避免过度使用它们:它会降低代码的可读性并导致错误。避免嵌套范围函数,并在链接它们时要小心:很容易对当前上下文对象和this
or 的值感到困惑it
。
takeIf
与 takeUnless
除范围函数外,标准库还包含函数takeIf
和takeUnless
。这些函数允许您在调用链中嵌入对象状态的检查。
在具有提供谓词的对象上调用时,如果该对象与谓词takeIf
匹配,则返回该对象。否则,它返回null
。因此,takeIf
是单个对象的过滤功能。反过来,takeUnless
如果对象与谓词不匹配则返回该对象,如果匹配则返回该对象null
。该对象可用作lambda参数(it
)。
val str = "Hello"
val caps = str.takeIf { it.isNotEmpty() }?.toUpperCase()
//val caps = str.takeIf { it.isNotEmpty() }.toUpperCase() //compilation error
println(caps)
在takeIf
和之后链接其他函数时takeUnless
,不要忘记执行空检查或安全调用(?.
),因为它们的返回值可以为空。
fun displaySubstringPosition(input: String, sub: String) {
input.indexOf(sub).takeIf { it >= 0 }?.let {
println("The substring $sub is found in $input.")
println("Its start position is $it.")
}
}
displaySubstringPosition("010000011", "11")
displaySubstringPosition("010000011", "12")
总结:
区别:
由于范围函数本质上非常相似,因此理解它们之间的差异非常重要。每个范围函数有两个主要区别:
- 引用上下文对象的方式
- 返回值。
apply:
上下文对象可用作receiver(this
)。返回值是对象本身
also:
上下文对象可用作参数(it
)。返回值是对象本身
上面两种返回都是对象本身可以调用链中以进行更复杂的处理。
---------------------------------------------------------------------------
run
与with
调用相同,作为let
上下文对象的扩展函数
let:
上下文对象可用作参数(it
)。返回值是lambda结果。
with:
非扩展函数:上下文对象作为参数传递,但在lambda中,它可用作receiver(this
)。返回值是lambda结果。
run:
上下文对象可用作receiver(this
)。返回值是lambda结果。
上面三种方式返回值是lambda结果。