88 votes

Kotlin : Quelle est la différence entre Apply et Also ?

Quelle est la différence entre appliquer et aussi. D'après ce que je sais, le code suivant fait la même chose :

appliquer

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

également

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

Y a-t-il une différence et dois-je utiliser l'un ou l'autre ? Par ailleurs, y a-t-il des cas où l'un fonctionnerait et l'autre pas ?

68voto

s1m0nw1 Points 21698

TL;DR Différence

En also reçoit un lambda, auquel T est passé dans l'implémentation, donc à l'intérieur de la lambda vous y faites référence avec un nom ( it par défaut, peut être renommé { otherName -> ...} ).

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

En apply d'autre part, une fonction littérale avec récepteur est utilisé, de sorte qu'à l'intérieur de la lambda passée, il n'est pas nécessaire d'ajouter des préfixes supplémentaires pour accéder à ses membres, comme vous le voyez dans ce qui suit. Le récepteur peut être référencé par this .

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

également

Déclaration :

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

Appelle le bloc fonctionnel spécifié avec this (le récepteur) comme argument et renvoie this (le destinataire).

appliquer

Déclaration :

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

Appelle le bloc fonctionnel spécifié avec this comme son destinataire et renvoie this (le destinataire).

quand utiliser quoi

Des exemples d'utilisation sont expliqués dans ce document fil .

51voto

Willi Mentzel Points 7681

Réponse courte : also a été introduit pour des raisons sémantiques.

Réponse longue :

Si vous utilisez apply vous vous référez toujours au récepteur avec this .

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

De cette manière, vous n'aurez pas à répéter la personne plusieurs fois comme indiqué ici :

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

Si le bloc s'allonge, il peut être utile d'ajouter this un nom. C'est pourquoi also a été introduite. Désormais, vous pouvez vous référer au récepteur soit par it ou un nom explicite. Ceci est particulièrement utile si vous souhaitez utiliser un autre nom que (dans ce cas-ci) person ) avant :

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

Ainsi, selon le degré de lisibilité de votre code, vous pouvez toujours utiliser l'un ou l'autre.

1voto

Sahil Patel Points 390

Les réponses données ci-dessus sont un peu logiques, mais pas beaucoup. Je n'ai pas bien compris, mais je voulais compléter la question ici.

Dans Standard.kt, il s'agit de l'implémentation réelle des deux méthodes.

Pour postuler

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

Car aussi

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

Les deux méthodes sont pratiquement identiques, à l'exception d'une ligne. Ce n'est qu'après avoir parcouru les explications que j'ai vu la différence. Un langage fonctionnel comme Kotlin est un véritable défi pour un développeur junior orienté Java comme moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X