Kotlin 标准库包含几个函数,它们的唯一目的是在对象的上下文中执行代码块。当对一个对象调用这样的函数并提供一个 lambda 表达式时,它会形成一个临时作用域。在此作用域中,可以访问该对象而无需其名称。这些函数称为作用域函数。共有以下五种:let
、run
、with
、apply
以及 also
。
这些函数基本上做了同样的事情:在一个对象上执行一个代码块。不同的是这个对象在块中如何使用,以及整个表达式的结果是什么。
作用域函数没有引入任何新的技术,但是它们可以使你的代码更加简洁易读。
由于作用域函数的相似性质,为选择正确的函数可能有点棘手。选择主要取决于你的意图和项目中使用的一致性。
函数 | 对象引用 | 返回值 | 是否是扩展函数 |
---|---|---|---|
let | it | Lambda 表达式结果 | 是 |
run | this | Lambda 表达式结果 | 是 |
run | - | Lambda 表达式结果 | 不是:调用无需上下文对象 |
with | this | Lambda 表达式结果 | 不是:把上下文对象当做参数 |
apply | this | 上下文对象 | 是 |
also | it | 上下文对象 | 是 |
以下是根据预期目的选择作用域函数的简短指南:
- 对一个非空(non-null)对象执行 lambda 表达式:
let
- 将表达式作为变量引入为局部作用域中:
let
- 对象配置:
apply
- 对象配置并且计算结果:
run
- 在需要表达式的地方运行语句:非扩展的
run
- 附加效果:
also
- 一个对象的一组函数调用:
with
不同函数的使用场景存在重叠,你可以根据项目或团队中使用的特定约定选择函数。
尽管作用域函数是使代码更简洁的一种方法,但请避免过度使用它们:这会降低代码的可读性并可能导致错误。避免嵌套作用域函数,同时链式调用它们时要小心:此时很容易对当前上下文对象及 this
或 it
的值感到困惑。
除了作用域函数外,标准库还包含函数 takeIf
及 takeUnless
。这俩函数使你可以将对象状态检查嵌入到调用链中。
当以提供的谓词在对象上进行调用时,若该对象与谓词匹配,则 takeIf
返回此对象。否则返回 null
。因此,takeIf
是单个对象的过滤函数。反之,takeUnless
如果不匹配谓词,则返回对象,如果匹配则返回 null
。该对象作为 lambda 表达式参数(it
)来访问。
当在 takeIf
及 takeUnless
之后链式调用其他函数,不要忘记执行空检查或安全调用(?.
),因为他们的返回值是可为空的。