Kotlin标准库 — — apply/also/run/let

Kotlin标准库中的apple/also/run/let这四个函数相当有意思。它们的实现非常简单,区区两三行,却直击了Java的若干痛点。

Kotlin对它们的定位是scope functions。这是什么意思呢?我理解,scope functions是指这些函数可以通过新的作用域操作对象,避免引入临时变量或一次性函数污染原作用域


首先,让我们来看看apply:

public inline fun  T.apply(block: T.() -> Unit): T {
    block()
    return this
}

寥寥数行,信息量却很大。

此函数有如下几个特点:

  1. 使用inline:跟C的inline类似,Kotlin的inline也是在编译期将函数调用直接在调用处展开,以节省函数调用的开销;所不同的是,Kotlin还会把传入的lambda函数也展开。
  2. 结合泛型和扩展,即T.apply,使得它成为了任意对象的成员函数
  3. 唯一的参数block是一个lambda函数,且block的参数是T.(),相当于为T扩展了一个无参的成员函数
  4. 由于applyblock都相当于是T的成员函数,在这两个函数的作用域里的this都指的是T的一个实例
  5. 执行传入的block,并返回this

apply如何使用呢?一个例子:

class House {
    val window = Window().apply {
        location = "Living Room"
        color = Color.WHITE
        size = Size.LARGE
    }
}

这个例子写成Java将会是这样:

class House {
    private final Window window = createWindow();

    private Window createWindow() {
        Window window = new Window();
        setLocation("Living Room");
        setColor(Color.WHITE);
        setSize(Size.LARGE);
        return window;
    }
}

可以看出,利用apply我们避免了引入createWindow这种一次性使用的函数污染House的成员。

(当然,对于上面的例子,我们可以通过给Window加一个Builder来避免引入额外的函数createWindow。但如果我们还需要调用setter以外的方法呢? )


下面,我们来看看also

public inline fun  T.also(block: (T) -> Unit): T {
    block(this)
    return this
}

诶?alsoapply不是一样的吗?非也。这两个函数对block的定义不同。之前的apply中,block的定义是T.() -> Unit,可作为T的扩展函数;而also的是(T) -> Unit,它没有扩展T,而是把T作为一个参数。

also适用于需要把T传递给其它对象的函数的场景。例如:

fun newHouseWithAWindow() { 
    return House()
        .add(Window())
        .also { log.debug("Created a new house with a window. house=$it") }
}

而用Java写的话,我们为了能够log返回值,需要引入一个局部变量:

Window newHouseWithAWindow() {
    House house = new House().add(new Window());
    log.debug("Created a new house with a window. {}", house);
    return house;
}

最后是runlet

public inline fun  T.run(block: T.() -> R): R = block()
public inline fun  T.let(block: (T) -> R): R = block(this)

runapply类似,letalso类似。所不同的是,这两个函数在执行完block之后,返回的是block的返回值,而非this

总而言之,这四个函数的异同点在于:

  1. 传入的block的作用域里的是this还是it
  2. 返回值是this还是block的执行结果
函数 block里 返回值
apply this this
also it this
run this block的结果
let it block的结果

那么,怎么选择应该用哪个函数呢?Kotlin官方文档Coding Conventions中有一节Using scope functions apply/with/run/also/let对此已有解答,这里不再赘述。

你可能感兴趣的:(Kotlin标准库 — — apply/also/run/let)