具有上限类型界限的案例类 [英] Case classes with an upper type bound

查看:19
本文介绍了具有上限类型界限的案例类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用具有上限类型界限的案例类和参数化类型时遇到了问题.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: E​​dge[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 的子类:IntEdgeStringEdge.第一个有一个 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 _

因为 EEdge 的任何子类,所以这是可以接受的.所以我们创建了一个 DOTExporteTS 传递给它.接下来,我们不使用 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屋!

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