首页 文章

Kotlin:Apply和Also之间有什么区别

提问于
浏览
21

申请和之间有什么区别 . 据我所知,下面的代码做了同样的事情:

apply

val person = Person().apply {
    name = "Tony Stark"
    age = 52
    // More such stuff
}

also

val person = Person().also {
  it.name = "Tony Stark"
  it.age = 52
  // More such stuff
}

有什么区别,我应该使用一个吗?此外,是否有一些情况下,一个人会工作,另一个不会?

3 回答

  • 14

    定义:

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

    调用指定的功能块 with this value as its argument 并返回该值 .

    适用

    定义:

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

    调用指定的功能块 with this value as its receiver 并返回该值 .

    差异

    also 函数接收一个lambda,在实现中传递 T ,因此在lambda中你用一个名称(默认为 it )引用它 .

    另一方面,在 apply 中,使用函数文字 with receiver ,因此在传递的lambda中,您不必添加其他前缀来访问其成员,如您在示例中所示 . 接收器可以由 this 引用 .

    何时使用什么

    用法示例在thread中进行了解释 .

  • 1

    Short answer: also 是出于语义原因而引入的 .

    Long answer:

    如果您使用 apply ,则始终使用 this 引用接收器 .

    val person = Person().apply {
        name = "Tony Stark" // this. can be omitted
        age = 52 // this. can be omitted
        // ...
    }
    

    这样你就不必重复几次了,如下所示:

    person.name = "Tony Stark"
    person.age = 52
    

    如果块变长,您可能想要给 this 一个名称 . 这就是 also 被引入的原因 . 现在您可以通过 it 或显式名称来引用接收器 . 如果您想在之前使用其他名称(在本例中为 person ),这将非常有用:

    val person = Person().also { newPerson ->
      newPerson.name = "Tony Stark"
      newPerson.age = 52
      // ...
    }
    

    因此,根据您的代码的可读性,您可以始终使用其中一个 .

  • 17

    上面给出的答案有点意义,但并不多 . 我不理解它,但我想在这里补充问题 .

    在Standard.kt中,这是两种方法的实际实现 .

    For apply

    /**
     * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
     */
    @kotlin.internal.InlineOnly
    public inline fun <T> T.apply(block: T.() -> Unit): T {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        block()
        return this
    }
    

    For also

    /**
     * Calls the specified function [block] with `this` value as its argument and returns `this` value.
     */
    @kotlin.internal.InlineOnly
    @SinceKotlin("1.1")
    public inline fun <T> T.also(block: (T) -> Unit): T {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        block(this)
        return this
    }
    

    除了一行之外,这两种方法几乎相同 . 只有经过解释后,我才看到了不同之处 . 像Kotlin这样的功能语言对于像我这样的Java思想的初级开发人员来说真的很有挑战性 .

相关问题