web-dev-qa-db-fra.com

Kotlin quadruple, quintuple, etc. pour la déstructuration

Je cherche un moyen propre de créer des objets destructurables en ligne. kotlin.Pair et kotlin.Triple couvre de nombreux cas d'utilisation, mais parfois il y a plus d'objets à passer.

Un exemple de cas d'utilisation est la fonction Zip de RX, où les résultats de plusieurs appels d'E/S doivent être mappés dans un autre objet:

Single
    .Zip(repositoryA.loadData(someId),
         repositoryB.loadData(someId),
         repositoryC.loadAll(),
         repositoryD.loadAll()),
         { objectA, objectB, objectsC, objectsD -> /*some Kotlin magic*/ }
    )
    .map { (objectA, objectB, objectsC, objectsD) -> /*do the mapping*/ }

J'essaie de comprendre ce qui se passerait dans la partie "un peu de magie Kotlin". S'il n'y avait que 3 référentiels, ce serait

Triple(objectA, objectB, objectsC)

Dois-je créer une nouvelle classe de données pour cela et pour tout cas n-Tuple, ou existe-t-il une autre façon?

18
kenny_k

Les bases

Voyons comment la déstructuration fonctionne:

Kotlin définit une convention pour cela, c'est-à-dire que les fonctions componentX()operator sont un exemple du principe des conventions utilisées dans Kotlin à de nombreux endroits. Ces fonctions componentX() sont utilisées par le compilateur pour l'initialisation des variables dans les déclarations de déstructuration.

Par exemple, dans Pair<A,B>, Ces fonctions se présentent comme suit:

operator fun component1(): A = first 

operator fun component2(): B = second

Comme vous pouvez le voir, ce sont operators , des fonctions spécialement gérées. Ces fonctions componentX() peuvent être fournies par le développeur et seront automatiquement produites par le compilateur pour les classes data. Pair est aussi une telle data classe btw.

Répondre

Ainsi, allez-y et utilisez les classes data chaque fois que vous avez besoin de plus d'un Triple.

Par exemple, une classe MultiComponent définie comme ceci:

data class MultiComponent(val x: Int, val y: Int, val z: Int, val a: Int, val b: Int, val c: Int)

sera compilé dans une classe avec les fonctions component1(), component2(), ..., component6() et peut être utilisé dans les déclarations de déstructuration:

val (q, w, e, r, t, z) = MultiComponent(1, 2, 3, 4, 5, 6)
18
s1m0nw1

Contrairement à Scala, Kotlin n'a pas de n-tuples pour des valeurs supérieures à 3 définies. Vous avez correctement identifié Pair et Triple.

Kotlin privilégie l'utilisation de classes de données pour ces cas d'utilisation, selon ce billet de blog . Alors oui, vous devrez définir une classe de données pour faire ce que vous voulez, il n'y a pas de Quadruple. Je dirais personnellement que la définition de votre propre classe de données est plus claire et finira par être compilée et utilisée de la même manière qu'un hypothétique Quadruple le ferait de toute façon, sous les couvertures.

En ce qui concerne la déstructuration des classes de données, Kotlin prend également en charge:

data class Thingy(val a: String, val b: String, val c: String, val d: String)
val t = Thingy("A", "B", "C", "D")
val (aa, bb, cc, dd) = t
9
Todd

J'ai trouvé plus simple de simplement coder les n-tuples nécessaires. Le cas d'utilisation était des méthodes d'extension fonctionnelles pour des choses comme la mémorisation, etc.

data class NTuple2<T1, T2>(val t1: T1, val t2: T2)

data class NTuple3<T1, T2, T3>(val t1: T1, val t2: T2, val t3: T3)

data class NTuple4<T1, T2, T3, T4>(val t1: T1, val t2: T2, val t3: T3, val t4: T4)

data class NTuple5<T1, T2, T3, T4, T5>(val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5)

data class NTuple6<T1, T2, T3, T4, T5, T6>(val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5, val t6: T6)

Et puis générez les aides à la construction nécessaires:

infix fun <T1, T2> T1.then(t2: T2): NTuple2<T1, T2>
{
    return NTuple2(this, t2)
}

infix fun <T1, T2, T3> NTuple2<T1, T2>.then(t3: T3): NTuple3<T1, T2, T3>
{
    return NTuple3(this.t1, this.t2, t3)
}

infix fun <T1, T2, T3, T4> NTuple3<T1, T2, T3>.then(t4: T4): NTuple4<T1, T2, T3, T4>
{
    return NTuple4(this.t1, this.t2, this.t3, t4)
}

infix fun <T1, T2, T3, T4, T5> NTuple4<T1, T2, T3, T4>.then(t5: T5): NTuple5<T1, T2, T3, T4, T5>
{
    return NTuple5(this.t1, this.t2, this.t3, this.t4, t5)
}

infix fun <T1, T2, T3, T4, T5, T6> NTuple5<T1, T2, T3, T4, T5>.then(t6: T6): NTuple6<T1, T2, T3, T4, T5, T6>
{
    return NTuple6(this.t1, this.t2, this.t3, this.t4, this.t5, t6)
}

Je pourrais alors faire:

val nTuple4 = 1 then 2 then "foo" then "bar"

Résultant en:

val nTuple4: NTuple4<Int, Int, String, String>
8
Dan Lugg

Vous pouvez ajouter ces classes kotlin à votre projet, elles fonctionneront exactement comme Pair ou Triple mais vous pourrez passer plus d'objets.

Quadruple (vous permet de passer 4 objets)

import Java.io.Serializable

/**
 * Created by nalcalag on 09/02/2019.
 * 
 * Represents a quartet of values
 *
 * There is no meaning attached to values in this class, it can be used for any purpose.
 * Quadruple exhibits value semantics
 *
 * @param A type of the first value.
 * @param B type of the second value.
 * @param C type of the third value.
 * @param D type of the fourth value.
 * @property first First value.
 * @property second Second value.
 * @property third Third value.
 * @property fourth Fourth value.
 */
data class Quadruple<out A, out B, out C, out D>(
        val first: A,
        val second: B,
        val third: C,
        val fourth: D
) : Serializable {

    /**
     * Returns string representation of the [Quadruple] including its [first], [second], [third] and [fourth] values.
     */
    override fun toString(): String = "($first, $second, $third, $fourth)"
}

/**
 * Converts this quadruple into a list.
 */
fun <T> Quadruple<T, T, T, T>.toList(): List<T> = listOf(first, second, third, fourth)

Quintuple (vous permet de passer 5 objets)

import Java.io.Serializable

/**
 * Created by nalcalag on 09/02/2019.
 * 
 * Represents a quartet of values
 *
 * There is no meaning attached to values in this class, it can be used for any purpose.
 * Quadruple exhibits value semantics
 *
 * @param A type of the first value.
 * @param B type of the second value.
 * @param C type of the third value.
 * @param D type of the fourth value.
 * @param E type of the fifth value.
 * @property first First value.
 * @property second Second value.
 * @property third Third value.
 * @property fourth Fourth value.
 * @property fifth Fifth value.
 */
data class Quintuple<out A, out B, out C, out D, out E>(
        val first: A,
        val second: B,
        val third: C,
        val fourth: D,
        val fifth: E
) : Serializable {

    /**
     * Returns string representation of the [Quintuple] including its [first], [second], [third], [fourth] and [fifth] values.
     */
    override fun toString(): String = "($first, $second, $third, $fourth, $fifth)"
}

/**
 * Converts this quadruple into a list.
 */
fun <T> Quintuple<T, T, T, T, T>.toList(): List<T> = listOf(first, second, third, fourth, fifth)
5
Noelia