我遇到了一个使用case类和带有上限类型的参数化类型的问题。
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)
}
}
这是我遇到问题的地方。我被告知Edge [BasicBlockVertex]是预期的,我只提供一个DefaultEdge。 DOTExport中的定义是class DOTExport[V <: VertexLike](val graph: GraphLike[V], val vertexToString: V => String, val edgeToString: Edge[V] => String)
所以现在我的问题是,我怎么还能为边类型使用case类并使编译器满意?我一定是个愚蠢的错误。
顺便说一句,匹配代码工作一次我说DefaultEdge(x,y)
而不是DefaultCase
等。然而DOTExport的实例化失败,因为Edge [?]是必需的并且我通过了CFG.E
谢谢!
编辑:事实上,GraphLike中的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)
}
}
答案 0 :(得分:3)
缺少太多能够真正帮助的人。您必须提供确切的错误消息,而不是解释它们。
无论如何,case DefaultEdge
表示传递的对象与对象DefaultEdge
之间的比较。后者是类DefaultEdge
的对象伴侣,通过使用case class
语句自动创建。此类伴随对象不属于属于它们所属的类。他们是单身人士,这意味着他们自己的班级本身就是独一无二的,否则,只是继承AnyRef
。
因此,换句话说,DefaultEdge
不是Edge
,这就是您收到错误的原因。至于使用DefaultEdge(_, _)
时出现的错误,你省略了太多细节。但是......你确定你这样编写代码吗?我希望以下内容:
new DOTExport(this, vertexToString _, edgeToString _)
修改强>
好的,第二条错误信息现在已经清楚了。 E
的原始声明是Edge
的子类,但是DOTExport
期待一个带Edge
的函数并转换它进入String
。要了解此处的问题,请注意以下定义也适用:
protected type E >: Edge[V]
让我们说,为了说明问题,您有两个Edge
的子类:IntEdge
和StringEdge
。第一个字段为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
字段,尝试运行它会在运行时导致异常,这会破坏静态类型的整个目的。
这是为了防止Scala不接受您的原始定义的这类问题。
答案 1 :(得分:2)
首先,Daniel非常正确,拥有更准确的信息会有很大帮助。但是,看起来你只需要同时做两件事:
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
!