当我遇到Case1
片段时,我正在查看github上的一个scala项目来学习scala。特征扩展了Scala Product
特征,然后案例对象扩展了该特征。编译得很好。
为了更好地理解这一点,我尝试了Case2
似乎没有编译,它要求我在case对象中定义absMethod()
。
我不明白为什么在第一种情况下不会发生这种情况。
//Case 1
sealed abstract trait test1 extends Product with Serializable
case object test11 extends test1
test11.productArity
//Case 2
trait abstact extends Any{
def absMethod():Int
}
sealed abstract trait test2 extends abstact
case object test22 extends test2
test22.absMethod()
答案 0 :(得分:5)
第一种情况是编译的,因为编译器对案例类/对象具有productArity
的特殊知识。作为编译过程的一部分,它不仅会创建一个伴随对象(对于案例类),还会实现多种方法,例如equals
,hashCode
,productArity
(以及更多) 。
如果你看一下typer阶段后的第一个测试的输出(scalac -Xprint:typer
):
sealed abstract trait test1 extends AnyRef with Product with Serializable;
case object test11 extends AnyRef with com.github.yuvalitzchakov.TupleTest.test1 with Product with Serializable {
def <init>(): com.github.yuvalitzchakov.TupleTest.test11.type = {
test11.super.<init>();
()
};
override <synthetic> def productPrefix: String = "test11";
<synthetic> def productArity: Int = 0;
<synthetic> def productElement(x$1: Int): Any = x$1 match {
case _ => throw new IndexOutOfBoundsException(x$1.toString())
};
override <synthetic> def productIterator: Iterator[Any] = scala.runtime.ScalaRunTime.typedProductIterator[Any](test11.this);
<synthetic> def canEqual(x$1: Any): Boolean = x$1.$isInstanceOf[com.github.yuvalitzchakov.TupleTest.test11.type]();
override <synthetic> def hashCode(): Int = -877171150;
override <synthetic> def toString(): String = "test11";
<synthetic> private def readResolve(): Object = com.github.yuvalitzchakov.TupleTest.test11
}
您可以看到编译器如何实现productArity
并指定0
(因为对象没有构造函数参数),这在Product
上是抽象的。对于自定义定义的抽象方法,您必须自己填充,因此编译器会在找不到实现时抱怨。
答案 1 :(得分:1)
这是因为case object
具体而且需要实现其抽象父类。例如,这将起作用并打印42
:
trait Abstract {
def method(): Int
}
sealed trait Test2 extends Abstract
case object Test22 extends Test2 {
def method(): Int = 42
}
Test22.method()
对于第一种情况,case class
es和case object
是Product
s,并且它们的字段是在编译时生成的。例如,包含两个字段的case class
也是Product
,其中包含{2},就像Tuple2[A, B]
((A, B)
,一对)。