2013-04-30 115 views
5

有人可以澄清爲什麼下面的代碼導致MatchError? MatchError在這種情況下意味着什麼?覆蓋配套對象值和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 

鑑於這種不工作,有沒有辦法來覆蓋同伴對象VAL或DEF與此類似?

回答

3

首先,爲什麼你看到MatchError。對象(A.f)上的值被認爲是一個穩定的標識符(正如Scala參考所述,「穩定的成員是由對象定義或非易失性類型的值定義引入的成員」)。

這裏的導電型測量儀輸出的樣子:

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

當在分配使用的,編譯器「desugars」這個穩定標識符的分配(它是穩定的必要條件)到模式匹配:

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

它不能匹配「對象B」與模式「對象A」,所以它會拋出MatchError

給你更大的問題:你不能/不應該覆蓋伴侶對象上的值和方法。多態性適用於類及其實例,而不適用於靜態方法或值。可能有更好的方式來思考你的程序,它不會覆蓋伴侶對象的vals/defs。

+0

感謝澄清!我同意你一般需要重寫companion對象,但是我想在這裏做的原因是爲了測試目的,我想用另一種方法替換伴隨對象中的方法。另外,一些語言允許重寫靜態方法。 – deepkimo 2013-04-30 21:05:37

1

這很有趣!如果你把類定義成一個文件,並使用scalac -print test.scala編譯它,你會看到這樣的事情,

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

這表明編譯器創建一個類B與執行的匹配檢查,看看該值初始化您用於覆蓋val A.f等於原始值if (A.f().==(x1))。似乎不太有用的權利?如果它們不相等,則通過調用case6()來引發匹配錯誤。我們可以通過將class B的定義更改爲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] 

那麼如何解決它呢?你可以做到這一點,

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 

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

你可能會考慮使用特質:http://stackoverflow.com/a/7625150/1274818 – tysonjh 2013-04-30 19:41:53

+0

你的修復是一個聰明的方式來解決這個簡單的代碼示例,但不是我真正想要的,因爲我想打電話給原始的Af方法。 – deepkimo 2013-04-30 21:10:25

+0

是的,特徵是一個很好的方式來構造這個,但在我的情況下,我想測試已經存在的代碼而不改變主代碼。 – deepkimo 2013-04-30 21:13:51