具有上限类型界限的案例类 [英] Case classes with an upper type bound
问题描述
我在使用具有上限类型界限的案例类和参数化类型时遇到了问题.Scala 编译器告诉我它找到类型 DefaultEdge
但需要 Edge[Type]
.我尝试使用类似 case DefaultEdge[Type]
的东西,但出现语法错误.
I ran into a problem using case classes and parameterized types with an upper type bound.
The Scala compiler tells me that it finds type DefaultEdge
but requires Edge[Type]
. I tried using something like case DefaultEdge[Type]
but I get syntax errors.
这是我的设置.我有几个对应于不同类型的边缘案例类.这些类包含参数化类型 V.
Here is my setup. I have a couple of edge case classes which correspond to different types. Those classes contain the parameterized 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
的特性,它定义了几个方法.唯一有趣的部分应该是这个:
Then I have a trait called GraphLike
which defines a couple of methods. The only interesting part should be this one:
trait GraphLike[V <: VertexLike] {
protected type E <: Edge[V]
}
中间的另一个 trait 实现了 GraphLike
trait 的一些方法,称为 GraphLikeWithAdjacencyMatrix
.当我将所有内容连接在一起时,我有以下课程:
Another trait in between implements some methods of the GraphLike
trait and is called GraphLikeWithAdjacencyMatrix
. When I wire everything together I have the following class:
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)
This is where I run into the problems. I get told that Edge[BasicBlockVertex] is expected and I only provide a DefaultEdge. The definition in DOTExport is class DOTExport[V <: VertexLike](val graph: GraphLike[V], val vertexToString: V => String, val edgeToString: Edge[V] => String)
所以我现在的问题是,我如何仍然为边缘类型使用案例类并使编译器满意?我一定是犯了一些愚蠢的错误.
So my question is now, how could I still use case classes for the edge types and make the compiler happy? It must be some stupid mistake on my side.
顺便说一下,一旦我说 DefaultEdge(x,y)
而不是 DefaultCase
等,匹配代码就起作用了.但是,DOTExport 的实例化失败了,因为 Edge[?] 是必需的,我通过了 CFG.E
By the way, the match-code works once I say DefaultEdge(x,y)
instead of DefaultCase
etc. However then the instantiation of DOTExport fails because Edge[?] is required and I pass a CFG.E
谢谢!
事实上,E = Edge[V]
在 GraphLike 和使用 DefaultEdge(_, _)
的组合是有效的.不幸的是,这只是尝试和错误的结果.我真的很想知道为什么它现在有效.
In fact the combination of E = Edge[V]
in GraphLike and using DefaultEdge(_, _)
works. This is unfortunately just the result of try and error. I would really like to know why it works now.
错误信息:
(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]
时一切正常,我不知道为什么.
Here is the full compilable code illustrating my problem. Again, my problem is line 14, since everything works when you replace type E <: Edge[V]
with type E = Edge[V]
and I have no idea why.
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)
}
}
推荐答案
缺少的东西太多,无法真正提供帮助.您必须提供准确的错误消息,而不是对其进行解释.
There's too much missing to be able to really help. You must provide the exact error messages, instead of paraphrasing them.
无论如何,case DefaultEdge
表示传递的对象与对象DefaultEdge
之间的比较.后者是 DefaultEdge
类的对象伴侣,通过使用 case class
语句自动创建.这样的伴随对象不属于它们所伴随的类.它们是单例,这意味着它们自己的类对它们自己是唯一的,否则,只需继承 AnyRef
.
At any rate, case DefaultEdge
means a comparision between the object passed and the object DefaultEdge
. The latter is the object companion of the class DefaultEdge
, automatically created through the use of the case class
statement. Such companion objects do not belong to the class they are companion to. They are singletons, which means their own classes are unique to themselves, and, otherwise, just inherit AnyRef
.
因此,换句话说,DefaultEdge
不是 Edge
,这就是您收到错误的原因.至于你在使用 DefaultEdge(_, _)
时遇到的错误,你忽略了太多细节.但是......你确定你是那样写代码的吗?我希望改为:
So, in other words, DefaultEdge
is not an Edge
, and that's why you get an error. As for the error you got when you used DefaultEdge(_, _)
, you ommitted too much detail. However... are you sure you wrote the code that way? I would expect the following instead:
new DOTExport(this, vertexToString _, edgeToString _)
编辑
好的,第二条错误信息现在清楚了.E
的原始声明是它是 Edge
的子类,但是 DOTExport
期望一个函数Edge
并将其转换为 String
.要理解这里的问题,请注意以下定义也适用:
Ok, the second error message is clear now. The original declaration of E
was that it was a subclass of Edge
, but DOTExport
is expecting a function that takes an Edge
and converts it into a String
. To understand the problem here, note that the following definition also works:
protected type E >: Edge[V]
假设,为了说明问题,您有两个 Edge
的子类:IntEdge
和 StringEdge
.第一个有一个 number
字段,第二个有一个 name
字段.因此,我们可以编写以下函数:
Let's say, to illustrate the problem, that you have two subclasses of Edge
: IntEdge
and StringEdge
. The first has a number
field, and the second a name
field. So, we could write the following functions:
def intEdgeToString(ie: IntEdge) = ie.number.toString
def stringEdgeToString(se: StringEdge) = se.name
现在,让我们创建一个 var
并存储其中之一:
Now, let's create a var
and store one of them:
var eTS: E => String = intEdgeToString _
因为 E
是 Edge
的任何子类,所以这是可以接受的.所以我们创建了一个 DOTExport
将 eTS
传递给它.接下来,我们不使用 IntEdge
提供 DOTExport
,而是使用 StringEdge
.由于后者没有 number
字段,尝试运行它会在运行时导致异常,这违背了静态类型的全部目的.
Since E
is any subclass of Edge
, this would be acceptable. So we create a DOTExport
passing eTS
to it. Next, we feed DOTExport
not with IntEdge
, but with StringEdge
. Since the latter do not have a number
field, trying to run it would cause an exception at run-time, which defeats the whole purpose of static typing.
Scala不接受你原来的定义就是为了防止这种问题.
It is to prevent this kind of problem that Scala did not accept your original definition.
这篇关于具有上限类型界限的案例类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!