2013-04-30 10 views
5

Czy ktoś może wyjaśnić, dlaczego poniższy kod powoduje błąd MatchError? Co oznacza w tym przypadku MatchError?Nadpisywanie wartości obiektów towarzyszących i Scala MatchError

class A { 
    def g = A.f 
} 

object A { 
    val f = "Object A" 
} 


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

val b = new B 
b.g 

Biorąc pod uwagę to, że nie działa, czy istnieje sposób na zastąpienie obiektu towarzyszącego val lub def podobnego do tego?

Odpowiedz

3

Po pierwsze, dlaczego widzisz MatchError. Wartość na obiekcie (A.f) jest uznawana za stabilny identyfikator (zgodnie z referencją Scala: "Elementy stabilne to [...] elementy wprowadzone przez definicje obiektów lub definicje wartości typów nielotnych").

Oto co wyjście typer wygląda następująco:

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

Kiedy stosuje się w zadania, kompilator „desugars” przypisanie tej stabilnej identyfikatora (to jest stabilny jest to warunek konieczny) do dopasowywania wzoru:

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

Nie można dopasować "Obiekt B" do wzorca "Obiekt A", więc rzuca MatchError.

Do większego pytania: nie można/nie należy zastępować wartości i metod na obiekcie towarzyszącym. Polimorfizm dotyczy klas i ich instancji, a nie statycznych metod lub wartości. Prawdopodobnie istnieje lepszy sposób myślenia o swoim programie, który nie obejmuje przesłonięcia vals/defs na obiekcie towarzyszącym.

+0

Dzięki za wyjaśnienie! Zgadzam się z tobą na temat potrzeby generowania nadrzędnych obiektów towarzyszących, ale powodem, dla którego chcę to zrobić, jest testowanie, w którym chcę zastąpić metodę wewnątrz obiektu towarzyszącego inną metodą. Ponadto niektóre języki umożliwiają nadpisywanie metod statycznych. – deepkimo

1

To jest interesujące! Jeśli umieścisz definicje klas do pliku i skompilować go za pomocą scalac -print test.scala widać coś takiego,

[[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 
     } 
     }; 
    () 
    } 
    } 
} 

To pokazuje, że kompilator tworzy klasę B z inicjalizacji, który wykonuje mecz sprawdzając, że wartości użyte w override val A.f jest równa oryginalnej wartości if (A.f().==(x1)). Czy nie wydaje się zbyt przydatne, prawda? Jeśli nie są równe, zgłasza błąd dopasowania, dzwoniąc pod numer case6(). Możemy to potwierdzić, zmieniając definicję class B na override val A.f = "Object A".

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

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

Jak to naprawić? Można to zrobić tylko,

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 

lub

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

Możesz rozważyć użycie cech: http://stackoverflow.com/a/7625150/1274818 – tysonjh

+0

Twoje poprawki to sprytny sposób na obejście tego prostego przykładu kodu, ale nie tego, czego naprawdę szukam, ponieważ chcę zadzwonić oryginalna metoda Af. – deepkimo

+0

Tak, cechy są dobrym sposobem na uporządkowanie tego, ale w moim przypadku chcę przetestować kod, który już istnieje bez zmiany kodu głównego. – deepkimo