我正在寻找一种干净的方式来在线创建可破坏的对象。 kotlin.Pair
和kotlin.Triple
涵盖了很多用例,但有时需要传递更多对象。
一个示例用例是RX的zip
函数,其中几个I / O调用的结果需要映射到另一个对象:
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*/ }
我正在试图找出"某些Kotlin魔法"部分。如果只有3个存储库,则为
Triple(objectA, objectB, objectsC)
我是否需要为此创建一个新的数据类,以及任何n元组的情况,还是有另一种方式?
答案 0 :(得分:10)
让我们看看解构的工作原理:
Kotlin为此定义了一个约定,即componentX()
operator
函数是Kotlin在许多地方使用的约定原则的一个例子。编译器使用这些componentX()
函数来初始化解构声明中的变量。
例如,在Pair<A,B>
中,这些函数如下所示:
operator fun component1(): A = first
operator fun component2(): B = second
如您所见,这些是operators
,特别处理的功能。
这些componentX()
函数可以由开发人员提供,并由编译器自动生成data
类。 Pair
也是data
类btw。
因此,只要您需要的时间超过data
,就可以继续使用Triple
课程。
例如,类MultiComponent
定义如下:
data class MultiComponent(val x: Int, val y: Int, val z: Int, val a: Int, val b: Int, val c: Int)
将编译为具有函数component1()
,component2()
,...,component6()
的类,并可用于解构声明:
val (q, w, e, r, t, z) = MultiComponent(1, 2, 3, 4, 5, 6)
答案 1 :(得分:7)
与Scala相反,Kotlin对于高于3定义的值没有n元组。您已正确识别Pair
和Triple
。
根据this blog post,Kotlin倾向于为这些用例使用数据类。所以,是的,你必须定义一个数据类才能做你想做的事情,没有Quadruple
。我个人认为定义自己的数据类更加清晰,并且最终会被编译和使用,与假设的Quadruple
一样,无论如何都会被覆盖。
至于解构数据类,Kotlin也支持这一点:
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
答案 2 :(得分:2)
我发现仅对所需的n元组进行代码生成是最简单的。用例是记忆等功能的扩展方法。
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)
然后生成必要的构造助手:
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)
}
所以我可以这样做:
val nTuple4 = 1 then 2 then "foo" then "bar"
结果:
val nTuple4: NTuple4<Int, Int, String, String>
答案 3 :(得分:0)
您可以将这些kotlin
类添加到您的项目中,它们将像Pair
或Triple
一样工作,但是您可以传递更多对象。
四重(让您传递4个对象)
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)
五合一(让您传递5个对象)
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)