覆盖Companion对象值和Scala MatchError

时间:2013-04-30 18:24:07

标签: oop scala override companion-object

有人可以澄清以下代码导致MatchError的原因吗?在这种情况下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?

2 个答案:

答案 0 :(得分:3)

首先,为什么你会看到MatchError。对象(A.f)上的值被认为是一个稳定的标识符(如Scala引用所示,“稳定成员是由对象定义或非易失性类型的值定义引入的成员”)。

这是typer输出的样子:

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。

答案 1 :(得分: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 = B@1fc6dc6

那么如何解决呢?你可以这样做,

class B extends A {
        override def g = "Object B"
}
scala> val b = new B
b: B = B@19bdb65

scala> b.g
res1: String = Object B

class B extends A {
        val f = "Object B"
}
scala> val b = new B
b: B = B@1e5ed7b

scala> b.f
res0: String = Object B