case类具有上部型界(Case classes with an upper type bound)

2019-10-18 21:06发布

我遇到了一个问题的情况下使用的类和参数化类型与结合的上型。 Scala编译器告诉我,找到键入DefaultEdge但需要Edge[Type] 。 我试图用类似case DefaultEdge[Type]但我得到的语法错误。

这里是我的设置。 我有几个对应于不同类型的边缘的情况下的类。 这些类包含的参数化类型V.

object EdgeKind extends Enumeration {
  type EdgeKind = Value
  val Default, Jump, True, False, DefaultCase, Case, Throw, Return = Value
}

sealed abstract class Edge[V <: VertexLike](val startVertex: V, val endVertex: V, val kind: EdgeKind.EdgeKind)

case class DefaultEdge[V <: VertexLike](override val startVertex: V, override val endVertex: V)
  extends Edge[V](startVertex, endVertex, EdgeKind.Default)
case class JumpEdge[V <: VertexLike](//...

然后,我有一个叫做特征GraphLike定义了几个方法。 唯一有趣的部分应该是这样:

trait GraphLike[V <: VertexLike] {
  protected type E <: Edge[V]
}

在之间的另一个特点实现的一些方法GraphLike特点,被称为GraphLikeWithAdjacencyMatrix 。 当我连线都在一起我有下面的类:

class CFG extends GraphLikeWithAdjacencyMatrix[BasicBlockVertex] {
  def dotExport = {
    def vertexToString(vertex: BasicBlockVertex) = ""
    def edgeToString(edge: E) = edge match {//also tried Edge[BasicBlockVertex] here
      case DefaultEdge => error("CFG may not contain default edges.")
      case JumpEdge => "jump"
      case TrueEdge => "true"
      case FalseEdge => "false"
      case DefaultCaseEdge => "default"
      case CaseEdge => "case"
      case ThrowEdge => "throw"
      case ReturnEdge => "return"
    }
    new DOTExport(this, vertexToString, edgeToString)
  }
}

这是我遇到的问题。 我得到告诉边缘[BasicBlockVertex]预计,我只能提供DefaultEdge。 在DOTExport的定义是class DOTExport[V <: VertexLike](val graph: GraphLike[V], val vertexToString: V => String, val edgeToString: Edge[V] => String)

所以我的问题是,现在,我怎么能仍然使用情况类边缘类型,使编译器高兴吗? 它必须是在我身边的一些愚蠢的错误。

顺便说一句,本场比赛,代码工作,一旦我说DefaultEdge(x,y)而不是DefaultCase等,但随后DOTExport的实例失败,因为边缘[?]是必需的,我通过CFG.E

谢谢!

编辑:实际上的组合E = Edge[V]在图式流和使用DefaultEdge(_, _)的工作原理。 这是很不幸的尝试和错误而造成的。 我真的想知道为什么现在的工作。

错误信息:

(fragment of test.scala):25: error:
type mismatch;  found   :
(Graph.this.E) => java.lang.String 
required: (this.Edge[?]) => String
    new DOTExport(this, (vertex: V) => vertex.toString, edgeToString)

这是说明我的问题完全编译代码。 同样,我的问题是14行,因为一切正常,当你更换type E <: Edge[V]type E = Edge[V]我不知道为什么。

object EdgeKind {
  val Default = 0
  val Jump = 1
}

abstract class Edge[V <: VertexLike](val startVertex: V, val endVertex: V, val kind: Int)

case class DefaultEdge[V <: VertexLike](override val startVertex: V, override val endVertex: V) extends Edge[V](startVertex, endVertex, EdgeKind.Default)
case class JumpEdge[V <: VertexLike](override val startVertex: V, override val endVertex: V) extends Edge[V](startVertex, endVertex, EdgeKind.Jump)

trait VertexLike

trait GraphLike[V <: VertexLike] {
  protected type E <: Edge[V] // Everything works when E = Edge[V]
}

class DOTExport[V <: VertexLike](val graph: GraphLike[V], val vertexToString: V => String, val edgeToString: Edge[V] => String)

class Graph[V <: VertexLike] extends GraphLike[V] {
  def dotExport = {
    def edgeToString(edge: E) = edge match {
      case DefaultEdge(_, _) => ""
      case JumpEdge(_, _) => "jump"
    }
    new DOTExport(this, (vertex: V) => vertex.toString, edgeToString)
  }
}

Answer 1:

有太多的缺失才能够真正的帮助。 您必须提供确切的错误信息,而不是意译他们。

无论如何, case DefaultEdge装置传递的对象和所述对象之间的对比DefaultEdge 。 后者是类的对象同伴DefaultEdge ,通过使用自动创建case class的语句。 这样的同伴对象属于他们同伴的类。 他们都是单身,这意味着自己的类是独一无二的自己,否则,只是继承AnyRef

因此,换句话说, DefaultEdge不是一个Edge ,这就是为什么你得到一个错误。 至于错误你有,当你使用DefaultEdge(_, _)你ommitted太多细节。 不过......你确定你写的代码呀? 我希望,而不是执行以下操作:

new DOTExport(this, vertexToString _, edgeToString _)

编辑

好了,现在第二个错误信息是明确的。 的正本报关E是,它的一个子类 Edge ,但DOTExport期待一个函数,它的Edge ,并将其转换成String 。 要了解这里的问题,注意以下定义也适用:

protected type E >: Edge[V]

比方说,为了说明问题,你有两个子类EdgeIntEdgeStringEdge 。 第一个拥有number场,第二个name字段。 所以,我们可以写如下功能:

def intEdgeToString(ie: IntEdge) = ie.number.toString
def stringEdgeToString(se: StringEdge) = se.name

现在,让我们创建一个var ,并将其储存之一:

var eTS: E => String = intEdgeToString _

由于E是任何子类Edge ,这是可以接受的。 所以我们创建了一个DOTExport通过eTS给它。 接下来,我们养活DOTExport不是IntEdge ,但StringEdge 。 由于后者没有number场,试图运行它会导致在运行时异常,这违背了静态类型的全部目的。

这是为了防止这样的问题,即斯卡拉不接受你的原始定义。



Answer 2:

首先,丹尼尔是相当正确的,具有更精确的信息,将有很大的帮助。 然而,它看起来像你只需要做你试过一起两件事:

def edgeToString(edge: Edge[BasicBlockVertex]) = edge match {
  case DefaultEdge(_,_) => error("CFG may not contain default edges.")
  case JumpEdge(_,_) => "jump"
  case TrueEdge(_,_) => "true"
  ...

因为1)的图案DefaultEdge错误的事情2)匹配edgeToString(edge: E) = ...意味着edgeToString具有类型CFG.E => String作为函数值使用而不是当Edge[V] => String等不能传递到new DOTExport



文章来源: Case classes with an upper type bound
标签: scala types