Scala 类型不匹配:需要 _$1,其中类型 _$1 <:

Scala type mismatch: required _$1 where type _$1 <:

我是 Scala 的新手,我遇到了一个我无法理解和解决的问题。我写了一个通用的 trait 就是这个:

trait DistanceMeasure[P<:DbScanPoint] {
  def distance(p1:P, p2:P):Double
}

其中 DbScanPoint 就是:

trait DbScanPoint extends Serializable {}

然后我有以下两个 classes 扩展它们:

class Point2d (id:Int, x:Double, y:Double) extends DbScanPoint {
   def getId() = id
   def getX() = x
   def getY() = y
}

class EuclideanDistance extends DistanceMeasure[Point2d] with Serializable {

   override def distance(p1:Point2d,p2:Point2d) = {
      (p1.getX()-p2.getX())*(p1.getX()-p2.getX()) + (p1.getY()-p2.getY()) * (p1.getY()-p2.getY())
  }
}

最后我有这个 class:

class DBScanSettings {

   var distanceMeasure:DistanceMeasure[_<:DbScanPoint] = new EuclideanDistance
   //...
}

我的问题是,如果当我在我的测试中写这个时:

 val dbScanSettings = new DBScanSettings()
 dbScanSettings.distanceMeasure.distance(new Point2d(1,1,1), new Point2d(2,2,2))

我得到以下编译错误:

 type mismatch;
 [error]  found   : it.polito.dbdmg.ontic.point.Point2d
 [error]  required: _ where type _ <: it.polito.dbdmg.ontic.point.DbScanPoint

我不明白是哪个问题。我对其他 classes 做了非常相似的事情,但我没有出错,所以这个错误的原因对我来说很模糊。

有人可以帮助我吗?

谢谢。

更新

我通过将代码更改为:

设法完成了我需要的操作
trait DistanceMeasure {
  def distance(p1:DbScanPoint, p2:DbScanPoint):Double
}

并且显然进行了所有相关更改。

你的问题的核心是你用一个存在类型定义你的 distanceMeasure var,所以编译器不完全知道该类型。然后,您正在调用 distance,这是将两个 P <: DbScanPoint 类型的实例传入两个 Point2d 实例。现在,这些是 distanceMeasure 后面的具体 class 的正确类型(一个新的 EuclideanDistance),但是您定义 distanceMeasure 的方式(具有存在性),编译器无法强制 Point2d 实例是具体底层 DistanceMeasure 所采用的正确类型。

出于争论的缘故,你不是使用新的 EuclideanDistance,而是实例化了一个完全不同的 DistanceMeasure 实现,它没有使用 Point2d 个实例,然后尝试调用 distance 他就是你在这里拥有它的方式。如果编译器不能强制底层 class 接受提供的参数,它会这样抱怨。

有很多方法可以解决这个问题,解决方案最终取决于您在 class 结构中需要的灵活性。一种可能的方式是这样的:

trait DBScanSettings[P <: DbScanPoint] {
  val distanceMeasure:DistanceMeasure[P]
 //...
}

class Point2dScanSettings extends DBScanSettings[Point2d]{
  val distanceMeasure = new EuclideanDistance
}

然后进行测试:

val dbScanSettings = new Point2dScanSettings()
dbScanSettings.distanceMeasure.distance(new Point2d(1,1,1), new Point2d(2,2,2))

但是如果我没有真正理解您对所需抽象级别的要求,则由您来定义重组。