I am looking for a clean way to create destructurable objects in-line. kotlin.Pair
and kotlin.Triple
cover a lot of use cases, but sometimes there are more objects that are needed to be passed.
One sample use case is RX's zip
function, where the results of several I/O calls need to be mapped into 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 am trying to figure out what would go in the "some Kotlin magic" part. If there were only 3 repositories, it 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?
Let's see how destructuring works:
Kotlin defines a convention for this, i.e. componentX()
operator
functions are an example of the principle of conventions used in Kotlin in many places. These componentX()
functions are used by the compiler for the initialization of variables in destructuring declarations.
For example in Pair<A,B>
these functions look as follows:
operator fun component1(): A = first
operator fun component2(): B = second
As you can see these are operators
, specially handled functions.
These componentX()
functions can be provided by the developer and will automatically be produced by the compiler for data
classes. Pair
also is such a data
class btw.
Thus, just go ahead and use data
classes whenever you need more than a Triple
.
For example, a class MultiComponent
defined as this:
data class MultiComponent(val x: Int, val y: Int, val z: Int, val a: Int, val b: Int, val c: Int)
will be compiled to a class with 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)