有人可以澄清为什么以下代码会导致 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 ?
有人可以澄清为什么以下代码会导致 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 ?
首先,为什么你会看到一个MatchError
. 对象 (Af) 上的值被认为是稳定标识符(正如 Scala 参考所说,“稳定成员是 [...] 由对象定义或非易失性类型的值定义引入的成员”)。
这是打字机输出的样子:
object A extends scala.AnyRef {
...
private[this] val f: String = "Object A";
<stable> <accessor> def f: String = A.this.f
}
当在赋值中使用时,编译器将这个稳定标识符(它是稳定的是必要条件)的赋值“去糖化”到模式匹配中:
<synthetic> private[this] val x$1: Unit = ("Object B": String("Object B") @unchecked) match {
case A.f => ()
}
它无法将“对象 B”与模式“对象 A”匹配,因此它会抛出MatchError
.
对于您更大的问题:您不能/不应该覆盖伴随对象上的值和方法。多态适用于类及其实例,而不适用于静态方法或值。可能有一种更好的方法来考虑您的程序,它不涉及在伴随对象上覆盖 vals/defs。
这是有趣的!如果您将类定义放入文件并使用它进行编译,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
我们可以通过更改 to 的定义来确认这一点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