0%

Kotlin常用内置函数

Kotlin标准库中,let, run, with, apply, also 这些函数在官方文档中称为 Scope Functions 。在结合 Lambda 表达式情况下,用这些函数写一些特定逻辑还是很方便的。

下面通过两个测试类阐述一下各个函数的使用方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Car {
}

public class Person {

private String name;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public void speak(String msg) {
System.out.println(msg);
}
}

run

1
public inline fun <R> run(block: () -> R): R

执行 Lambda,并返回 Lambda 的结果

例如通过 Lambda 执行一些逻辑,生成某个对象并获取其引用

1
2
3
4
var car: Car = run {
// ......
Car()
}

这个 run 方法不需要对象,可以直接调用

T.run

1
public inline fun <T, R> T.run(block: T.() -> R): R

在某个对象上执行 Lambda,将此对象作为 Lambda 的接收者。
可以在 Lambda 中使用this引用,返回 Lambda 执行结果。

例如

1
2
3
4
var car: Car = person.run {
this.speak("person.run")
Car()
}

person 对象上执行 run,可通过 this 调用 Person 类中的方法。最后返回生成的 Car 对象。

with

1
public inline fun <T, R> with(receiver: T, block: T.() -> R): R

和上面的 run 有些类似,不过这里不用通过 person 对象来调用了,直接调用 with 方法即可。同样返回 Lambda 执行的结果。

例如

1
2
3
4
val car: Car = with(person) {
this.speak("person.with")
Car()
}

T.apply

1
public inline fun <T> T.apply(block: T.() -> Unit): T

在给定对象上执行 Lambda,同样将这一对象作为接收者。最后返回这个对象自身。

非常适合用来创建对象,并且最后返回对象自身,可进一步调用其公开方法。感觉和 Builder 模式有些类似。在 Lambda中,调用对象自身方法可以省略 this

1
2
3
4
5
6
7
var person: Person = Person().apply {
this.age = 20
name = "Jack"
}.apply {
this.speak("Hello")
speak("World")
}

T.also

1
public inline fun <T> T.also(block: (T) -> Unit): T

类似 apply,区别在于将对象作为参数传进 Lambda 中,而不是作为 Lambda 的接收者。在 Lambda中以 it 作为对象引用(也可以显示指定名称)。

例如

1
2
3
4
5
6
7
person.also {
it.speak("person.speak")
}

person.also { he ->
he.speak("person.speak")
}

T.let

1
public inline fun <T, R> T.let(block: (T) -> R): R

将对象作为参数传进 Lambda,执行并返回 Lambda 结果。

例如

1
2
3
4
var car: Car = person.let {
it.speak("person.let")
Car()
}

T.takeIf

1
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T?

将对象作为参数传进 Lambda,当 Lambda 执行结果 true 时,返回此对象,否则返回 null

例如

1
2
3
4
5
6
var child: Person? = Person().apply {
age = 20
}.takeIf {
it.age < 18
}
println(child)

因为年龄不小于18,打印结果是 null

T.takeUnless

1
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T?

takeIf 相反,当 Lambda 执行结果为 true 时,返回 null,否则返回此对象

例如

1
2
3
4
5
6
var adult: Person? = Person().apply {
age = 20
}.takeUnless {
it.age < 18
}
println(adult)

打印结果不为空

repeat

1
public inline fun repeat(times: Int, action: (Int) -> Unit)

重复执行 Lambda N 次,将循环 Index 传进 Lambda中

例如

1
2
3
repeat(3) {
person.speak("speak $it times")
}

打印结果

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