可以通过多种方式来做到这一点,这些方式都或多或少像 Randall Schulz 在评论中描述的那样。Shapeless库提供了一个特别方便的实现,它可以让你得到非常接近你想要的东西,如下所示:
import shapeless._
case class EuclideanPoint[N <: Nat](
coordinates: Sized[IndexedSeq[Double], N] { type A = Double }
) {
def distanceTo(destination: EuclideanPoint[N]): Double =
math.sqrt(
(this.coordinates zip destination.coordinates).map {
case (a, b) => (a - b) * (a - b)
}.sum
)
}
现在您可以编写以下内容:
val orig2d = EuclideanPoint(Sized(0.0, 0.0))
val unit2d = EuclideanPoint(Sized(1.0, 1.0))
val orig3d = EuclideanPoint(Sized(0.0, 0.0, 0.0))
val unit3d = EuclideanPoint(Sized(1.0, 1.0, 1.0))
和:
scala> orig2d distanceTo unit2d
res0: Double = 1.4142135623730951
scala> orig3d distanceTo unit3d
res1: Double = 1.7320508075688772
但不是:
scala> orig2d distanceTo unit3d
<console>:15: error: type mismatch;
found : EuclideanPoint[shapeless.Nat._3]
required: EuclideanPoint[shapeless.Nat._2]
orig2d distanceTo unit3d
^
Sized
带有许多不错的功能,包括一些带有关于长度的静态保证的集合操作。例如,我们可以编写以下内容:
val somewhere = EuclideanPoint(Sized(0.0) ++ Sized(1.0, 0.0))
并且在三维空间中拥有一个普通的老点。