2012-03-27 4 views
1

Ich habe eine Klasse, die in einer Sitzung serialisiert und deserialisiert wird, und ich muss Mustererkennung für innere Klassen durchführen. Ich habe Probleme mit der Identität der inneren Klassen:Fixing-Fall Objekt Identität/Mustererkennung unter Serialisierung

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' 

Was für eine elegante Art und Weise ist die Identität für EmptyValue nicht ‚zu entkommen Pfadabhängigkeit‘ zu beheben, so zu sprechen. Ich habe Code wie die folgenden, die bricht, wenn die Serialisierung stattfindet:

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

Das heißt, obwohl der Compiler mein Spiel sagt erschöpfende ist, erhalte ich eine Laufzeit MatchError wenn Serialisierung mit (I benutzerdefinierten Code habe, dass schreibt in/liest aus Byte-Arrays). Zum Beispiel rufe ich von innerhalb des Baumes, der [email protected] hat und einen Tree$EmptyValu[email protected] abruft und sie nicht zusammenpassen.

EDIT

ich weitere Tests durchgeführt habe, weil ich wirklich die inneren Typen zu vermeiden, möchte darauf bewegen, wie sie benötigen, um Typ-Parameter und damit brechen alle passenden Codemuster. Es sieht aus, als ob das Problem nur mit diesen speziellen case object auftritt:

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 

Antwort

2

Existentialtyp könnte dies ausdrücken.

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 

Bytecode für 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 
... 
+0

Das ist toll Eugene. Weißt du, ob diese Definition von "equals" eine Art von Laufzeit-Penalität darstellt (eine andere Reflektion als 'isInstanceOf')? –

+0

Ich habe mir die Freiheit genommen, Ihre Antwort zu bearbeiten, den resultierenden Byte-Code zu zeigen und somit meine Kommentarfrage zu beantworten - es scheint, dass dies eine wirklich 'billige' Operation ist :) –

1

Wenn ich verstehe, was Sie versuchen, richtig zu tun, können Sie versuchen, ein Begleitobjekt für Baum Hinzufügen und Definieren von EmptyValue darin:

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

Das Problem ist, ist Baum tatsächlich in drei Typen parametrisiert, so 'Tree [S, D, A]'. Ich kann den Mustervergleich nur verwenden, wenn ich innere Typen verwende, weil sich sonst der beschissene Matcher über die Art des Löschens beschwert. Es ist eine ziemlich komplexe Datenstruktur, die das Verschieben der inneren Typen kostet mich einen Arbeitstag. Ich habe die Frage bearbeitet, um zu zeigen, dass dies seltsamerweise nur ein Problem von "Fallobjekten" ist, wie es scheint. –

Verwandte Themen