Исправление идентичности объекта case / сопоставления с образцом при сериализации - PullRequest
1 голос
/ 27 марта 2012

У меня есть класс, который сериализуется и десериализуется в сеансе, и мне нужно выполнить сопоставление с образцом для внутренних классов. У меня проблемы с идентичностью внутренних классов:

class Tree(val id: Int) {
  override def hashCode = id
  override def equals(that: Any) = that.isInstanceOf[Tree] &&
    that.asInstanceOf[Tree].id == id

  case object EmptyValue
}

val t1 = new Tree(33)
val t2 = new Tree(33)

t1 == t2 // ok 
t1.EmptyValue == t2.EmptyValue // wrong -- reports 'false'

Какой элегантный способ исправить идентификатор для EmptyValue, чтобы он не назывался, так сказать, «зависимостью от пути выхода». У меня есть код, подобный следующему, который ломается, когда происходит сериализация:

def insert(point: Point, leaf: Leaf): Unit = {
  val qidx = hyperCube.indexOf(point)
  child(qidx) match {
    case EmptyValue => ...
    ...
  }
}

То есть, хотя компилятор говорит, что мое совпадение является исчерпывающим , я получаю время выполнения MatchError при использовании сериализации (у меня есть специальный код, который записывает / читает из байтовых массивов). Например, я звоню из дерева с Tree$EmptyValue$@4636 и получаю Tree$EmptyValue$@3601, и они не совпадают.

EDIT

Я провел дополнительные тесты, потому что я действительно хотел бы избежать перемещения внутренних типов, так как они должны будут иметь параметры типа и таким образом нарушать весь код сопоставления с образцом. Похоже, что проблема возникает только с этим конкретным case object:

class Tree {
  sealed trait LeftChild
  case object  EmptyValue   extends LeftChild
  sealed trait LeftNonEmpty extends LeftChild
  final case class LeftChildBranch() extends LeftNonEmpty

  def testMatch1(l: LeftChild) = l match {
    case EmptyValue        => "empty"
    case LeftChildBranch() => "non-empty"
  }

  def testMatch2(l: LeftChild) = l match {
    case EmptyValue      => "empty"
    case n: LeftNonEmpty => "non-empty"
  }
}

val t1 = new Tree
val t2 = new Tree

t1.testMatch1(t2.LeftChildBranch().asInstanceOf[t1.LeftChild])       // works!!!
t1.testMatch2(t2.LeftChildBranch().asInstanceOf[t1.LeftChild])       // works!!!
t1.testMatch1(t2.EmptyValue.asInstanceOf       [t1.EmptyValue.type]) // fails

Ответы [ 2 ]

2 голосов
/ 27 марта 2012

Экзистенциальный тип может выразить это.

scala> case class Tree(id: Int) {
     |    case object EmptyValue {
     |       override def hashCode = 0
     |       override def equals(that: Any) = that.isInstanceOf[x.EmptyValue.type forSome { val x: Tree }]
     |    }
     | }
defined class Tree

scala> val t1 = Tree(33)
t1: Tree = Tree(33)

scala> val t2 = Tree(33)
t2: Tree = Tree(33)

scala> t1.EmptyValue == t2.EmptyValue
res0: Boolean = true

Байт-код для equals:

scala> :javap -v Tree.EmptyValue

...
public boolean equals(java.lang.Object);
  Code:
   Stack=1, Locals=2, Args_size=2
   0:   aload_1
   1:   instanceof  #23; //class Tree$EmptyValue$
   4:   ireturn
...
1 голос
/ 27 марта 2012

Если я понимаю, что вы пытаетесь сделать правильно, вы можете попробовать добавить объект-компаньон для Tree и определить в нем EmptyValue:

class Tree( val id: Int ) { /******/ }
object Tree {
  case object EmptyValue
}
...