Scala 案例对象扩展特征的行为差异
我正在github上查看一个scala项目来学习scala,这时我遇到了Scala 案例对象扩展特征的行为差异,scala,Scala,我正在github上查看一个scala项目来学习scala,这时我遇到了Case1片段。trait扩展Scala产品trait,然后case对象扩展该trait。这个编译得很好。 为了更好地理解这一点,我尝试了Case2,它似乎没有编译,它要求我在case对象中定义absMethod()。 我不明白为什么在第一种情况下不会发生这种情况 //Case 1 sealed abstract trait test1 extends Product with Serializable case objec
Case1
片段。trait扩展Scala产品
trait,然后case对象扩展该trait。这个编译得很好。
为了更好地理解这一点,我尝试了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()
这是因为
case对象是具体的,需要实现其抽象父类。例如,这将起作用并打印42
:
trait Abstract {
def method(): Int
}
sealed trait Test2 extends Abstract
case object Test22 extends Test2 {
def method(): Int = 42
}
Test22.method()
对于第一种情况,case类
es和case对象
s是Product
s,它们的字段在编译时生成。例如,一个带有两个字段的case类
也是一个带有算术2的产品
,就像一个Tuple2[a,B]
((a,B)
,一对)。这是因为case对象
是具体的,需要有其抽象父类的实现。例如,这将起作用并打印42
:
trait Abstract {
def method(): Int
}
sealed trait Test2 extends Abstract
case object Test22 extends Test2 {
def method(): Int = 42
}
Test22.method()
对于第一种情况,case类
es和case对象
s是Product
s,它们的字段在编译时生成。例如,一个带有两个字段的案例类
也是一个具有算术2的产品
,就像Tuple2[a,B]
((a,B)
,一对)。第一个案例是编译的,因为编译器对案例类/对象具有产品性
的特殊知识。作为编译过程的一部分,它不仅会创建一个伴生对象(用于case类),还会实现多种方法,例如equals
、hashCode
、productArity
(以及更多)
如果在打字机阶段之后查看第一次测试的输出(scalac-Xprint:typer
):
sealed abstract trait test1使用可序列化的产品扩展AnyRef;
案例对象test11使用com.github.yuvalitzchakov.TupleTest.test1和可序列化的产品扩展AnyRef{
def():com.github.yuvalitzchakov.TupleTest.test11.type={
测试11.super.();
()
};
覆盖def productPrefix:String=“test11”;
def生产率:Int=0;
def productElement(x$1:Int):任意=x$1匹配{
case=>抛出新的IndexOutOfBoundsException(x$1.toString())
};
重写def productIterator:Iterator[Any]=scala.runtime.ScalaRunTime.typedProductIterator[Any](test11.this);
def canEqual(x$1:Any):Boolean=x$1.$isInstanceOf[com.github.yuvalitzchakov.TupleTest.test11.type]();
覆盖def hashCode():Int=-877171150;
重写def toString():String=“test11”;
private def readResolve():Object=com.github.yuvalitzchakov.TupleTest.test11
}
您可以看到编译器如何实现productArity
并分配0
(因为对象没有构造函数参数),这在Product
上是抽象的。对于自定义的抽象方法,您必须自己填充它,因此编译器在找不到实现时会抱怨。第一种情况是编译的,因为编译器对案例类/对象的生产性有专门的了解。作为编译过程的一部分,它不仅会创建一个伴生对象(用于case类),还会实现多种方法,例如equals
、hashCode
、productArity
(以及更多)
如果在打字机阶段之后查看第一次测试的输出(scalac-Xprint:typer
):
sealed abstract trait test1使用可序列化的产品扩展AnyRef;
案例对象test11使用com.github.yuvalitzchakov.TupleTest.test1和可序列化的产品扩展AnyRef{
def():com.github.yuvalitzchakov.TupleTest.test11.type={
测试11.super.();
()
};
覆盖def productPrefix:String=“test11”;
def生产率:Int=0;
def productElement(x$1:Int):任意=x$1匹配{
case=>抛出新的IndexOutOfBoundsException(x$1.toString())
};
重写def productIterator:Iterator[Any]=scala.runtime.ScalaRunTime.typedProductIterator[Any](test11.this);
def canEqual(x$1:Any):Boolean=x$1.$isInstanceOf[com.github.yuvalitzchakov.TupleTest.test11.type]();
覆盖def hashCode():Int=-877171150;
重写def toString():String=“test11”;
private def readResolve():Object=com.github.yuvalitzchakov.TupleTest.test11
}
您可以看到编译器如何实现productArity
并分配0
(因为对象没有构造函数参数),这在Product
上是抽象的。对于自定义的抽象方法,您必须自己填充,因此编译器在找不到实现时会抱怨。是的,我知道,但我不明白为什么在第一种情况下我没有看到任何错误。对不起,我没有正确回答问题。添加了一个澄清,希望这有帮助。是的,我知道,但我不明白为什么在第一种情况下,我没有看到任何错误。对不起,我没有得到正确的问题。添加了一个澄清,希望这有帮助。谢谢你的问题,我发布了一个答案,希望能澄清你的疑问。除此之外,还有一些关于代码的注意事项:您不必显式扩展Any
(一个扩展“nothing”的类隐式扩展Any
),也不必将trait
注释为abstract
。这是不正确的。当类、特征或对象没有显式扩展任何内容时,它会自动扩展AnyRef
。如果您有一个扩展了AnyVal
的类,并且希望它从trait继承,那么该trait需要显式扩展Any
。谢谢