当通用类型对相同的通用类型进行操作时,Scala类型不匹配 [英] Scala Type mismatch when a generic type operates on the same generic type

查看:47
本文介绍了当通用类型对相同的通用类型进行操作时,Scala类型不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通用的案例类Route,它接受一个Location的子类列表.但是,在以下方法中,我在对 distance expected:head.T,实际:T

I have an generic case class Route that takes in a List of subclasses of Location. However in the following method I get a type mismatch in the call to distance expected: head.T, actual: T

case class Route[T <: Location](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)
  }
}

基本的抽象Location类如下

The basic abstract Location class is as follows

abstract class Location(val name: String) {

type T <: Location

def distance(that: T): Double
}

head和h都来自同一列表 route ,我不明白为什么它们不是同一类型.

As head and h both come from the same list route I can't understand why these are not the same type.

推荐答案

在这种情况下,您似乎想要的是F界多态性:

It looks as if F-bounded polymorphism is what you want in this case:

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:

However, you might also consider using a Metric-typeclass instead:

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)
  }
}

后一种解决方案将适用于更多类型,例如,适用于(Double,Double),即使它们不继承自 Location .

The latter solution would be applicable to more types, for example to (Double, Double), even if they don't inherit from Location.

这里再次是类型类解决方案,但具有稍微更优美的Cats风格的语法,从而避免了隐式:

Here is the typeclass solution again, but with slightly more polished Cats-style syntax that avoids 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)
  }
}

这篇关于当通用类型对相同的通用类型进行操作时,Scala类型不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆