2013-04-30 119 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