集合中的Scala案例类

Joa*_*ert 6 scala

场景:我正在解析IL并且想要从基于堆栈的表示转换为CFG.

我的IL包含多个操作,如PushInt(值),Pop等.问题是现在哪个实现在Scala方面是正确的.我很乐意使用案例类/对象或提取器,以便我可以编写代码

op match {
  case PushInt(x) => doSomethingWith x
  case Pop => ...
}
Run Code Online (Sandbox Code Playgroud)

现在问题存在于一个序列,PushInt(1) :: PushInt(1) :: Pop :: Pop因为PushInt(1)等于PushInt(1)并且我不能将多个(相等)操作添加到集合中.但是我知道我正在抛出一些信息,这是流程中的位置,但是这被隐含地存储为序列中的te索引.

  • 一种可能的解决方案是覆盖hashCode方法并破坏equal/hashCode的规则.我对此并不满意.

  • 另一个选择是有一个"创建时间"计数器,存储在抽象基础中,以便 case class PushInt(value: Int) extends AbstractOp(AbstractOp.nextIndex)

  • 使用提取器,但在这种情况下,我将错过很好的功能,如hashCode,equals,toString的实现,更重要的是检查详尽的匹配.

所以我现在的问题是如何根据我的要求对我的结构进行建模.在Scala方面,任何可能的解决方案都是"正确的"吗?

Dan*_*ral 5

首先,让我们解决找到你想要的确切实例的问题:

scala> trait AbstractOp
defined trait AbstractOp

scala> case class Pop() extends AbstractOp {
     |   override def equals(other: Any) = other match {
     |     case that: Pop => this eq that
     |     case _ => false
     |   }
     | }
defined class Pop

scala> case class PushInt(val i: Int) extends AbstractOp {
     |   override def equals(other: Any) = other match {
     |     case that: PushInt => this eq that
     |     case _ => false
     |   }
     | }
defined class PushInt

scala> val l = List(PushInt(1), PushInt(1), Pop(), Pop())
l: List[Product with AbstractOp] = List(PushInt(1), PushInt(1), Pop(), Pop())

scala> val op = l(1)
op: Product with AbstractOp = PushInt(1)

scala> println( l.indexOf( op ) )
1
Run Code Online (Sandbox Code Playgroud)

当然,这意味着PushInt(1) != PushInt(1),除非它是完全相同的实例PushInt(1).它没有破坏equals/ hashCode收缩,因为a.equals(b) => a.hashCode == b.hashCode,但a.hashCode == b.hashCode并不意味着什么.但如果您唯一的用途是找到该实例,请尝试以下方法:

scala> case class Pop() extends AbstractOp
defined class Pop

scala> case class PushInt(val i: Int) extends AbstractOp
defined class PushInt

scala> val l = List(PushInt(1), PushInt(1), Pop(), Pop())
l: List[Product with AbstractOp] = List(PushInt(1), PushInt(1), Pop(), Pop())

scala> val op = l(1)
op: Product with AbstractOp = PushInt(1)

scala> println( l.findIndexOf( op eq _ ) )
1
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,如果您在列表中重新插入该实例,您将遇到麻烦.您必须确保插入的每个实例都是唯一的.您甚至可以编写自己的集合,如果插入重复的实例则抛出异常,或者为传递给它的任何实例制作副本(copy在Scala 2.8上使用case类和方法很容易).