如何命名一对

时间:2018-01-07 00:52:20

标签: kotlin tuples

鉴于Pair val coordinates = Pair(2, 3),是否可以为每个值命名,以便我可以执行coordinates.x之类的操作来返回2?或coordinates.first是访问第一个值的唯一方法吗?

6 个答案:

答案 0 :(得分:7)

不支持此功能。您应该为此目的编写一个包装器(数据)类,或者您可以使用Kotlin解构声明:

val (x, y) = coordinates
println("$x;$y")

查看更多here

答案 1 :(得分:6)

另一个解决方案是为object定义一个Pair<A, B>有意义的扩展名,并使用with(...) { ... }将这些扩展带入上下文。

object PointPairs {
    val <X> Pair<X, *>.x get() = first
    val <Y> Pair<*, Y>.y get() = second
}

用法:

val point = Pair(2, 3)

with(PointPairs) {
    println(point.x)
}

这允许您为同一类型提供多组扩展,并在适当的地方使用它们。

答案 2 :(得分:5)

Kotlin stdlib中Pair的定义如下:

public data class Pair<out A, out B>(
    public val first: A,
    public val second: B
) : Serializable

因此,如果您有p类型的实例Pair,则只能以p.first的形式访问第一个属性。但是,您可以像这样使用Destructuring Declaration

val (x, y) = p

这是可能的,因为Pairdata class。数据类的主要构造函数的每个参数都获得componentX()方法,其中X是参数的索引。所以上面的调用可以这样表达:

val x = p.component1()
val y = p.component2()

这使它完全独立于参数的实际名称。

但是,如果您希望能够编写p.x,则必须继续创建自己的数据类(或使用库):

data class Point(val x : Double, val y : Double)

答案 3 :(得分:3)

我想提出一个替代方案,如果仅在某个范围内需要重命名,则应该应用该替代方案。

您可以创建一个简单的扩展高阶函数,在范围内命名,作为lambda参数传递:

<_io.TextIOWrapper name='playlist2.txt' mode='a' encoding='UTF-8'>

现在,可以使用lambda调用fun <F, S> Pair<F, S>.named(block: (F, S) -> Unit) = block(first, second) ,该lambda使用在调用者站点上可命名的组件调用:

Pair

甚至可以应用invoke convention

val pair = Pair(2, 3)
pair.named { x, y ->
    println("my pair: ($x,$y)")
}

现在,可以直接调用operator fun<F, S> Pair<F, S>.invoke(block: (F, S) -> Unit) = block(first, second)

Pair

答案 4 :(得分:0)

Kotlin documetation说:

  

标准库提供Pair和Triple。但在大多数情况下,   命名数据类是一个更好的设计选择,因为他们制作了   通过为属性提供有意义的名称来使代码更具可读性。

由于Pair是最终的,遗憾的是你不能继承它,但我建议创建一个专用的类Point

data class Point<T>(var x: T, var y: T)

代表一个观点。这样,无论您在何处使用它,您都必须使用有意义的名称来访问它。

使用它:

val myPoint = Point(1.0, 2.0)
println("This is the horizontal coordinate: ${myPoint.x}")

答案 5 :(得分:0)

我在这里为提高代码可读性而喜欢做的另一件事是使用typealias(或更新的内联类,但目前仍处于试验阶段)

所以您可以这样做:

typealias Radius = Double?
typealias Area= Float

然后做:Pair<Area,Radius> 因此它更具可读性,但是对于访问描述,我将做数据类。

您可以更进一步:

typealias  DimensionsPair = Pair<Area,Radius>

请注意,我认为这里的内联类将带来更好的类型安全性。