在这种情况下,您想要的似乎是 F 有界多态性:
abstract class Location[L <: Location[L]](val name: String) {
def distance(that: L): Double
}
case class Route[T <: Location[T]](route: List[T]) {
def measureDistance: Double = {
def measure(head: T, tail: List[T], acc: Double = 0.0): Double = tail match {
case Nil => acc
case h :: t => measure(h, t, head.distance(h) + acc)
}
if (route.isEmpty) 0.0
else measure(route.head, route.tail)
}
}
但是,您也可以考虑使用Metric
-typeclass 代替:
trait Metric[L] {
def dist(a: L, b: L): Double
}
case class Route[T: Metric](route: List[T]) {
def measureDistance: Double = {
def measure(head: T, tail: List[T], acc: Double = 0.0): Double = tail match {
case Nil => acc
case h :: t => measure(h, t, implicitly[Metric[T]].dist(head, h) + acc)
}
if (route.isEmpty) 0.0
else measure(route.head, route.tail)
}
}
后一种解决方案将适用于更多类型,例如 to (Double, Double)
,即使它们不继承自Location
.
这里又是 typeclass 解决方案,但使用了稍微更精致的 Cats 风格的语法,避免了implicitly
:
trait Metric[L] {
def dist(a: L, b: L): Double
}
object Metric {
def apply[T](implicit m: Metric[T]): Metric[T] = m
}
case class Route[T: Metric](route: List[T]) {
def measureDistance: Double = {
def measure(head: T, tail: List[T], acc: Double = 0.0): Double = tail match {
case Nil => acc
case h :: t => measure(h, t, Metric[T].dist(head, h) + acc)
}
if (route.isEmpty) 0.0
else measure(route.head, route.tail)
}
}