当泛型类型在相同的泛型类型上运行时,Scala类型不匹配

时间:2018-06-08 09:44:11

标签: scala generics types f-bounded-polymorphism

我有一个通用案例类Route,它接受Location的子类列表。但是,在以下方法中,我在调用server { listen 80; server_name ""; root /var/www/html/site/web; location / { try_files $uri /app.php$is_args$args; } location ~ ^.*/(app_dev|config)\.php(/|$) { fastcgi_pass lockate_site:9000; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $document_root; } } 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)
  }
}

由于head和h都来自同一个列表abstract class Location(val name: String) { type T <: Location def distance(that: T): Double } ,我无法理解为什么这些类型不同。

3 个答案:

答案 0 :(得分:3)

在这种情况下看起来好像是F-bounded多态:

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 - 类型代码:

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继承。

这是类型类解决方案,但是使用稍微更优雅的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)
  }
}

答案 1 :(得分:0)

您无需在ACT_HI_PROCINST抽象类中定义类型T。您应该按照以下步骤进行操作:

Location

答案 2 :(得分:0)

scala编译器无法知道类type T <: Location中定义的Location与Route的类型参数[T <: Location]的类型相同。

我认为你必须要签署def distance(...)的签名。我不确定,但如果你将T定义为Location的类型参数:

,它应该可以工作
abstract class Location[T <: Location[T]](val name: String) {
  def distance[T](that: T): Double
}