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

时间:2017-09-09 13:36:56

标签: kotlin

申请和之间有什么区别。据我所知,以下代码执行相同的操作:

应用

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

同时

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

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

4 个答案:

答案 0 :(得分:20)

TL; DR差异

also函数接收一个lambda,T在实现中传递给它,因此在lambda中你引用一个名称(默认为it),可以重命名{ otherName -> ...})。

val person = Person().also {
    it.name = "Tony Stark"
}

另一方面,在apply中,使用了函数文字 with receiver ,因此在传递的lambda中,您不必添加额外的前缀来访问其成员,如你在下面看到。接收者可以由this引用。

val person = Person().apply {
    name = "Tony Stark"
}

宣言:

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

使用this(接收方)值作为参数调用指定的功能块,并返回this(接收方)值。

应用

宣言:

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

使用this值作为接收器调用指定的功能块,并返回this(接收方)值。

何时使用

thread中解释了用法示例。

答案 1 :(得分:15)

简短回答: also是出于语义原因而引入的。

答案很长:

如果您使用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
  // ...
}

因此,根据您的代码的可读性,您可以随时使用其中一种。

答案 2 :(得分:5)

  • 两个函数都返回接收者对象本身。
  • 它们在访问接收器对象方面有所不同。

enter image description here

由您决定使用哪个。但是,在Kotlinlang的网站https://kotlinlang.org/docs/reference/scope-functions.html中,有一个约定使用它们

还将用于不会改变对象的其他操作,例如记录或打印调试信息。

val numbers = mutableListOf("one", "two", "three")
 numbers
     .also { println("The list elements before adding new one: $it") }
     .add("four")

应用的常见情况是对象配置。

val adam = Person("Adam").apply {
    age = 32
    city = "London"        
}
println(adam)

答案 3 :(得分:1)

上面给出的答案有点意义,但并不多。我没有正确理解它,但我想在这里添加问题。

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

申请

/**
 * 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
}

也适用于

/**
 * 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思想的初级开发人员来说真的很有挑战性。