加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala – 在编译时强制执行Vector的大小

发布时间:2020-12-16 09:27:24 所属栏目:安全 来源:网络整理
导读:是否可以在编译时强制传入方法的Vector的大小?我想使用空间中的点集合来建模一个n维欧几里德空间,看起来像这样(这就是我现在所拥有的): case class EuclideanPoint(coordinates: Vector[Double]) { def distanceTo(desination: EuclieanPoint): Double = ?
是否可以在编译时强制传入方法的Vector的大小?我想使用空间中的点集合来建模一个n维欧几里德空间,看起来像这样(这就是我现在所拥有的):

case class EuclideanPoint(coordinates: Vector[Double]) {
  def distanceTo(desination: EuclieanPoint): Double = ???
}

如果我有一个通过EuclideanPoint(Vector(1,0))创建的坐标,它是一个3D欧几里德点.鉴于此,我想确保在对distanceTo的调用中传递的目标点具有相同的维度.

我知道我可以通过使用Tuple1到Tuple22来做到这一点,但我想代表许多不同的几何空间,如果我用元组做的话,我会为每个空间写22个类 – 有更好的方法吗?

解决方法

可以通过多种方式实现这一点,所有这些方式或多或少都与Randall Schulz在评论中描述的方式相似. Shapeless library提供了一个特别方便的实现,它可以让你得到一些非常接近你想要的东西:

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
                                ^

Size带有许多不错的功能,包括一些带有静态保证长度的收集操作.我们可以编写以下代码:

val somewhere = EuclideanPoint(Sized(0.0) ++ Sized(1.0,0.0))

并且在三维空间中有一个普通的旧点.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读