Scala 修复序列化下的大小写对象标识/模式匹配
我有一个在会话中被序列化和反序列化的类,我需要对内部类执行模式匹配。我对内部类的身份有问题:Scala 修复序列化下的大小写对象标识/模式匹配,scala,serialization,equals,case-class,Scala,Serialization,Equals,Case Class,我有一个在会话中被序列化和反序列化的类,我需要对内部类执行模式匹配。我对内部类的身份有问题: 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
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
(我有一个自定义代码,可以写入/读取字节数组)。例如,我在树中调用树$EmptyValue$@4636
并检索树$EmptyValue$@3601
,但它们不匹配
编辑
我已经进行了进一步的测试,因为我真的希望避免将内部类型移出,因为它们需要类型参数,从而破坏所有模式匹配代码。问题似乎只发生在特定的案例对象上:
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
如果我了解您正试图正确执行的操作,您可以尝试为Tree添加一个伴生对象并在其中定义EmptyValue:
class Tree( val id: Int ) { /******/ }
object Tree {
case object EmptyValue
}
存在主义类型可以表达这一点
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
的字节码等于
:
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
...
问题是,树实际上被参数化为三种类型,因此树[S,D,A]
。我只能在使用内部类型时使用模式匹配,否则糟糕的匹配程序会抱怨类型擦除。这是一个相当复杂的数据结构,将内部类型移出将花费我一天的工作。我编辑了这个问题,以表明奇怪的是,这似乎只是案例对象的问题。这太棒了,尤金。你知道等于
的定义是否会造成某种运行时惩罚(反射而不是isInstanceOf
)?我冒昧地编辑了你的答案,显示了结果字节码,从而回答了我的评论问题——这似乎是一个非常“便宜”的操作:)