2013-04-30 8 views

Antwort

3

Zuerst, warum Sie eine MatchError sehen. Ein Wert für ein Objekt (A.f) wird als stabiler Bezeichner betrachtet (wie in der Scala-Referenz heißt, "stabile [...] Mitglieder sind Mitglieder, die durch Objektdefinitionen oder Wertdefinitionen nichtflüchtiger Typen eingeführt werden").

Hier ist, was die typer Ausgabe wie folgt aussieht:

object A extends scala.AnyRef { 
    ... 
    private[this] val f: String = "Object A"; 
    <stable> <accessor> def f: String = A.this.f 
} 

Wenn in einer Zuweisung verwendet wird, der Compiler „desugars“ Zuordnung dieses stabilen Identifikator (es stabil zu sein, ist eine notwendige Bedingung) in Mustervergleich:

<synthetic> private[this] val x$1: Unit = ("Object B": String("Object B") @unchecked) match { 
    case A.f =>() 
} 

Es kann "Objekt B" nicht mit einem Muster "Objekt A" übereinstimmen, so dass es eine MatchError wirft.

Zu Ihrer größeren Frage: Sie können Werte und Methoden auf einem Begleitobjekt nicht überschreiben/sollten. Polymorphismus gilt für Klassen und ihre Instanzen, nicht für statische Methoden oder Werte. Es gibt wahrscheinlich eine bessere Möglichkeit, über Ihr Programm nachzudenken, bei dem Vals/Defs auf einem Begleitobjekt nicht überschrieben werden.

+0

Danke für die Aufklärung! Ich stimme Ihnen mit der Notwendigkeit überein, Begleitobjekte im Allgemeinen zu überschreiben, aber der Grund, warum ich das hier tun möchte, ist zu Testzwecken, wo ich eine Methode innerhalb des Begleitobjekts durch eine andere Methode ersetzen möchte. Außerdem erlauben einige Sprachen das Überschreiben von statischen Methoden. – deepkimo

1

Das ist interessant! Wenn Sie die Klassendefinitionen in einer Datei speichern, und kompilieren Sie es scalac -print test.scala wird bereitet Sie etwas sehen,

[[syntax trees at end of     cleanup]] // scala 
package <empty> { 
    class A extends Object { 
    def g(): String = A.f(); 
    def <init>(): A = { 
     A.super.<init>(); 
    () 
    } 
    }; 
    object A extends Object { 
    private[this] val f: String = _; 
    <stable> <accessor> def f(): String = A.this.f; 
    def <init>(): A.type = { 
     A.super.<init>(); 
     A.this.f = "Object A"; 
    () 
    } 
    }; 
    class B extends A { 
    <synthetic> private[this] val x$1: runtime.BoxedUnit = _; 
    def <init>(): B = { 
     B.super.<init>(); 
     B.this.x$1 = { 
     case <synthetic> val x1: String = ("Object B": String("Object B")); 
     case5(){ 
      if (A.f().==(x1)) 
      { 
       val x2: String = x1; 
       matchEnd4(scala.runtime.BoxedUnit.UNIT) 
      } 
      else 
      case6() 
     }; 
     case6(){ 
      matchEnd4(throw new MatchError(x1)) 
     }; 
     matchEnd4(x: runtime.BoxedUnit){ 
      scala.runtime.BoxedUnit.UNIT 
     } 
     }; 
    () 
    } 
    } 
} 

Dies zeigt, dass der Compiler eine Klasse erstellt B mit einer Initialisierung, die eine Übereinstimmung, dass der Wert, um zu sehen Überprüfung durchführt Sie verwendet in Override die val A.f ist gleich dem ursprünglichen Wert if (A.f().==(x1)). Scheint nicht zu nützlich zu sein, oder? Wenn sie nicht gleich sind, wird der Übereinstimmungsfehler durch Aufruf von case6() ausgelöst. Wir können dies bestätigen, indem wir die Definition des class B zu override val A.f = "Object A" ändern.

class B extends A { 
     override val A.f = "Object A" 
} 

scala> val b = new B 
b: B = [email protected] 

So, wie es zu beheben? Sie können dies nur tun,

class B extends A { 
     override def g = "Object B" 
} 
scala> val b = new B 
b: B = [email protected] 

scala> b.g 
res1: String = Object B 

oder

class B extends A { 
     val f = "Object B" 
} 
scala> val b = new B 
b: B = [email protected] 

scala> b.f 
res0: String = Object B 
+0

Sie können die Verwendung von Merkmalen in Betracht ziehen: http://StackOverflow.com/a/7625150/1274818 – tysonjh

+0

Ihre Korrekturen sind eine kluge Möglichkeit, um dieses einfache Codebeispiel zu umgehen, aber nicht das, wonach ich wirklich suche, da ich das aufrufen möchte Original-Af-Methode. – deepkimo

+0

Ja, Traits sind eine gute Möglichkeit, dies zu strukturieren, aber in meinem Fall möchte ich Code testen, der bereits existiert, ohne den Hauptcode zu ändern. – deepkimo