Kotlin four, fivefold, etc. For restructuring

I am looking for a clean way to create destructible objects in a string. kotlin.Pair and kotlin.Triple cover many use kotlin.Triple , but sometimes there are more objects that need to be passed.

One use case is the RX zip function, where the results of multiple I / O calls need to be matched against another object:

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

I'm trying to figure out what will be in "some Kotlin magic." If there were only 3 repositories, that would be

 Triple(objectA, objectB, objectsC) 

Do I need to create a new data class for this and for any n-tuple case, or is there another way?

+9
source share
4 answers

the basics

Let's see how destruction works:

Kotlin defines a convention for this, that is, the operator functions of componentX() are an example of the convention principle used in Kotlin in many places. These componentX() functions are used by the compiler to initialize variables in destructuring declarations.

For example, in Pair<A,B> these functions look like this:

 operator fun component1(): A = first operator fun component2(): B = second 

As you can see, these are operators , specially processed functions. These componentX() functions can be provided by the developer and automatically generated by the compiler for the data classes. Pair also such a data class by the way.

Answer

So, just go ahead and use the data classes when you need more than Triple .

For example, the MultiComponent class MultiComponent defined as follows:

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

will be compiled into a class with the functions component1() , component2() , ..., component6() and can be used in destructuring declarations:

 val (q, w, e, r, t, z) = MultiComponent(1, 2, 3, 4, 5, 6) 
+9
source

Unlike Scala, Kotlin does not have n-tuples for values ​​higher than 3. You correctly defined Pair and Triple .

Kotlin advocates using data classes for these use cases, according to this blog post . So yes, you will need to define a data class to do what you want, no Quadruple . I personally argue that the definition of your own data class is more understandable, and in the end it will be compiled and used in the same way as the hypothetical Quadruple will be under the covers anyway.

Regarding the restructuring of data classes, Kotlin also supports this:

 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 
+6
source

I found that the easiest way is to simply encode the necessary n-tuples. Use cases are functional extension methods for things like memorization, 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) 

And then generate the necessary construction assistants:

 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) } 

So what I could do then:

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

As a result:

 val nTuple4: NTuple4<Int, Int, String, String> 
+1
source

You can add these kotlin classes to your project, they will work just like Pair or Triple but you can pass more objects.

Four-block (allows you to pass 4 objects)

 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) 

Fivefold (allows you to go through 5 objects)

 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) 
0
source

Source: https://habr.com/ru/post/1271765/


All Articles