鉴于Pair val coordinates = Pair(2, 3)
,是否可以为每个值命名,以便我可以执行coordinates.x
之类的操作来返回2
?或coordinates.first
是访问第一个值的唯一方法吗?
答案 0 :(得分:7)
答案 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
这是可能的,因为Pair
是data 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)
标准库提供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>
请注意,我认为这里的内联类将带来更好的类型安全性。