Kotlin标准库中,let
, run
, with
, apply
, also
这些函数在官方文档中称为 Scope Functions 。在结合 Lambda 表达式情况下,用这些函数写一些特定逻辑还是很方便的。
1 | public class Car { |
run
1 | public inline fun <R> run(block: () -> R): R |
执行 Lambda,并返回 Lambda 的结果
例如通过 Lambda 执行一些逻辑,生成某个对象并获取其引用
1 | var car: Car = run { |
这个 run
方法不需要对象,可以直接调用
T.run
1 | public inline fun <T, R> T.run(block: T.() -> R): R |
在某个对象上执行 Lambda,将此对象作为 Lambda 的接收者。
可以在 Lambda 中使用this引用,返回 Lambda 执行结果。
例如
1 | var car: Car = person.run { |
在 person 对象上执行 run
,可通过 this 调用 Person
类中的方法。最后返回生成的 Car
对象。
with
1 | public inline fun <T, R> with(receiver: T, block: T.() -> R): R |
和上面的 run
有些类似,不过这里不用通过 person 对象来调用了,直接调用 with
方法即可。同样返回 Lambda 执行的结果。
例如
1 | val car: Car = with(person) { |
T.apply
1 | public inline fun <T> T.apply(block: T.() -> Unit): T |
在给定对象上执行 Lambda,同样将这一对象作为接收者。最后返回这个对象自身。
非常适合用来创建对象,并且最后返回对象自身,可进一步调用其公开方法。感觉和 Builder 模式有些类似。在 Lambda中,调用对象自身方法可以省略 this
1 | var person: Person = Person().apply { |
T.also
1 | public inline fun <T> T.also(block: (T) -> Unit): T |
类似 apply
,区别在于将对象作为参数传进 Lambda 中,而不是作为 Lambda 的接收者。在 Lambda中以 it 作为对象引用(也可以显示指定名称)。
例如
1 | person.also { |
T.let
1 | public inline fun <T, R> T.let(block: (T) -> R): R |
将对象作为参数传进 Lambda,执行并返回 Lambda 结果。
例如
1 | var car: Car = person.let { |
T.takeIf
1 | public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? |
将对象作为参数传进 Lambda,当 Lambda 执行结果 true 时,返回此对象,否则返回 null
例如
1 | var child: Person? = Person().apply { |
因为年龄不小于18,打印结果是 null
T.takeUnless
1 | public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? |
和 takeIf
相反,当 Lambda 执行结果为 true 时,返回 null,否则返回此对象
例如
1 | var adult: Person? = Person().apply { |
打印结果不为空
repeat
1 | public inline fun repeat(times: Int, action: (Int) -> Unit) |
重复执行 Lambda N 次,将循环 Index 传进 Lambda中
例如
1 | repeat(3) { |
打印结果
speak 0 times
speak 1 times
speak 2 times
方法的选择
Kotlin官方文档中介绍了这些函数对应的场景。同时建议不要过度使用这些函数,以避免降低代码可读性。
Funtion | Object reference | Return value | Is extension funtion |
---|---|---|---|
let | it | Lambda result | Yes |
run | this | Lambda result | Yes |
run | - | Lambda result | No:called without the context object |
with | this | Lambda result | No:takes the context object as an argument |
apply | this | Context object | Yes |
also | it | Context object | Yes |
- Executing a lambda on non-null objects: let
- Introducing an expression as a variable in local scope: let
- Object configuration: apply
- Object configuration and computing the result: run
- Running statements where an expression is required: non-extension run
- Additional effects: also
- Grouping function calls on an object: with