Scala中的自定义和多构造函数继承?
据我所知,自定义构造函数的语义通常可以通过伴生对象添加到类中。那么,在继承类的同时,是否有任何方法可以继承自定义构造函数 一方面,我发现伴随对象不是沿着case类综合继承的,另一方面,我不知道如何在类本身内部创建自定义构造函数,以便继承它们。然而,对我来说,继承自定义构造函数似乎是一个完全有效的用例。那么Scala是否以某种(直接的)方式支持它呢 天真的意图证明:Scala中的自定义和多构造函数继承?,scala,Scala,据我所知,自定义构造函数的语义通常可以通过伴生对象添加到类中。那么,在继承类的同时,是否有任何方法可以继承自定义构造函数 一方面,我发现伴随对象不是沿着case类综合继承的,另一方面,我不知道如何在类本身内部创建自定义构造函数,以便继承它们。然而,对我来说,继承自定义构造函数似乎是一个完全有效的用例。那么Scala是否以某种(直接的)方式支持它呢 天真的意图证明: class A {} object A { def apply(n: Int) = { println(n) n
class A {}
object A {
def apply(n: Int) = {
println(n)
new A
}
}
class B extends A {}
object Test {
val a1 = A
val a2 = A(3)
val b1 = B // compile error
val b2 = B(3) // compile error
另外,我甚至在一个定制构造函数中发现了一个事实上并没有被继承的结果(它只适用于创建定制构造函数,但奇怪的是,不幸的是这些构造函数并没有被继承)。演示代码:
class A {
def this(n: Int) = {
this
println(n)
}
}
class B extends A {}
object Test {
val a1: A = new A
val a2: A = new A(3)
val b1 = new B
val b2 = new B(3) // compile error
}
编辑意图的澄清:
考虑到这个问题,“构造函数”和“伴随工厂方法”可以互换。Scala中的构造函数在类的主体中定义,并在类名之后使用参数,例如
class A(i: Int) {
println(i)
}
本例中的println(i)
是构造函数逻辑。如果现在扩展A,如下所示:
class B(i: Int) extends A(i)
并实例化B
,valb1=newb(2)
,您将看到构造函数确实是继承的
正如您已经发现的,Scala允许您通过定义名为this
的函数来定义替代构造函数。但是这些替代构造函数必须调用主构造函数
我的理解是,任何Scala类实际上只有一个构造函数,其他构造函数只是过滤到其中。例如:
class A(x: Int, y: Int) {
// do some constructing!
def this(x: Int) = {
this(x, 1) // provide a default value for y
}
}
你不能直接继承构造函数,因为你不能,你也不能在不做一点工作的情况下继承使用它们的东西。但是您可以抽象出构造函数调用之外的任何内容 让我们假设我们有
class Foo(text: String) {
override def toString = "Foo: " + text
}
object Foo {
def apply(text: String) = new Foo(text) // Auto-generated for case class
def apply(i: Int) = new Foo(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
然后我们决定
class Bar(text: String) extends Foo(text) {
override def toString = "Bar: " + text
}
现在,我们如何处理对象栏
?我们没有重新编写所有逻辑,而是创建了一个特征,将对象创建与构造函数参数的计算分离并抽象:
所以,您不能完全摆脱样板文件,但可以将其简化为从一个trait和一个方法调用进行扩展
如果您这样做(抽象apply
与构造函数完美匹配),您甚至可以让案例类工作,而无需手动定义附带的抽象apply
方法:
case class Baz(text: String) extends Foo(text) {
override def toString = "Baz: " + text
}
object Baz extends FooCompanionLike[Baz] {
// Nothing here! Auto-generated apply works!
}
简而言之:没有直截了当的方法;试着绕开并抵制这种欲望。你在这里描述的构造函数实际上并不是一个构造函数。它只是一个在伴生对象上的函数应用程序(在内部调用构造函数)。谢谢,好的,把它称为工厂方法。在scala中,这不是实现自定义构造函数/多个构造函数语义的唯一技术吗?顺便说一句,对于类型参数化类,而不是扩展类,
上述样式的此
自定义构造函数可以工作,而伴随对象则不能。谢谢,但这并不能解决问题的意图(可能只有@resueman的技术注释),它实现了一个可继承的工厂方法,以及许多这样的方法。我不确定继承工厂方法是否有意义。类a上的工厂方法是一个接受0个或多个参数并返回a的函数,例如(…)=>A.如果B扩展了A,并且继承了工厂函数,它仍然会返回A而不是B。您将不得不定义一个新函数(…)=>B恐怕再次,您的评论是关于技术术语而不是意图的语义。无论如何,谢谢。构造函数确实没有被继承。中定义了new
的语义“模板评估"谢谢。Java是否表现出同样的继承限制?也许恢复到类型参数化工厂类将是一个等效的解决方法。@matt-这就是伴生对象的实际情况。在Java中,这只是更尴尬,因为需要手动执行更多的操作。我们能不能更进一步,在中使create
具体化oCompanionLike
从而消除了Foo
和Bar
对象中的冗余实现,以及一些ClassTag
magic?我说的对吗,我们仍然需要继承类并为其硬编码工厂对象?如果是这样,在某些情况下,我可能只使用fa来绕过我的初衷ctory类,它将包含(并允许访问)它正在创建的类,因此在这个方案中用户只有一个继承,但这可能会带来一些其他限制。无论如何,再次感谢!我看到你去掉了\u text
参数,但我实际上认为了隐藏参数的问题以及缺少一种方法来以一种看不见的、自动的方式“传递”参数确实与这个问题有关,因为它涉及到主要的ctor。在这个上下文中提到同伴特征是聪明和恰当的!这个答案比我所能做到的更短、更具讽刺意味。
object Foo extends FooCompanionLike[Foo] {
def apply(text: String) = new Foo(text)
}
object Bar extends FooCompanionLike[Bar] {
def apply(text: String) = new Bar(text)
}
case class Baz(text: String) extends Foo(text) {
override def toString = "Baz: " + text
}
object Baz extends FooCompanionLike[Baz] {
// Nothing here! Auto-generated apply works!
}