我想在抽象类中定义一个构造函数,它将创建具体的子类。
abstract class A {
type Impl <: A
def construct() : Impl = {
val res = new Impl() //compile error: class type required but A.this.Impl found
// do more initialization with res
}
}
class B extends A {type Impl = B}
class C extends A {type Impl = C}
//...
val b = new B
b.construct() // this should create a new instance of B
这里有什么问题?这甚至可以实现吗?
编辑:澄清:我想抽象构造方法。我不想从子类或伴随对象中单独调用new B
和new C
。
答案 0 :(得分:2)
如果要创建新实例,则需要显式调用构造函数。
abstract class A {
def newInstance(): this.type;
def construct() : this.type = {
val res = newInstance()
}
}
class B extends A {
def newInstance() = new B()
}
Scala在运行时擦除类型,因此无法知道在创建类时Impl的含义。
答案 1 :(得分:1)
您可以将构造函数放在随播对象中,而不是在抽象类中。像这样:
object A {
def apply(i:Int):A = new B(...)
def apply(s:String):A = new C(...)
}
现在,您可以通过调用A
或A(42)
来创建A("foobar")
的实例。当然,字符串和整数参数仅是示例。如果所有构造函数的参数具有相同的类型,则此重载将不起作用。在这种情况下,您可以轻松创建不同的方法,并将其称为apply
以外的其他方法。
答案 2 :(得分:1)
您可以使用反射来创建新实例。像这样的东西会起作用,但在我看来并不值得。首先,您只能检查运行时是否存在合适的构造函数。
def newInstance[T:ClassManifest]:T = {
val klass = implicitly[ClassManifest[T]].erasure
val constr = klass.getConstructors()(0)
constr.newInstance().asInstanceOf[T]
}
abstract class A {
def construct(implicit cm:ClassManifest[this.type]): this.type = {
val res = newInstance[this.type]
res
}
}
class B extends A
答案 3 :(得分:0)
看起来这是不可能的。根据Scala的书(由Oderski,Spoon,Venners),您无法创建抽象类型的实例。请参阅:摘要类型章节,货币案例研究。稍后可以使用“虚拟类”来支持此功能。
答案 4 :(得分:0)
我提出以下模式:
abstract class A($params) {
// do common initialisation here
def construct() : A
def foo(...) = {
...
val bar = construct()
...
}
}
class B($moreparams) extends A($someparams) {
// do special initialisation here
def construct() = new B()
}
您现在拥有的所有减少量恰好是每个子类一行。我认为这是一个很小的代价来支付a)一个工作解决方案,b)不使用反射(这基本上打破了静态类型系统为你提供的所有保证)。
我仍然很好奇你在construct
内需要A
的原因。闻起来很腥。
答案 5 :(得分:0)
在Monkey
回复后留下我的评论。解决此问题的一种方法是将Curiously Recurring Template Pattern(CRTP)与自我类型一起使用:
abstract class A[T <: A[T]] { this: T =>
def newInstance(): T;
def construct(): T = {
val res = newInstance()
res
}
def some(): T = this
}
class B extends A[B] {
def newInstance() = new B()
}
也许有一个更好的解决方案,但这是我发现的目标。