私が持っているとしましょう:
trait A
class B extends A
class C extends A
次のようなタイプ パラメータを設定する方法はありますか。
class Foo[AType <: A with canCreateInstance]
def newAType : AType = new AType
Foo は、B や C などの A を実装するクラスのみを取得でき、A 自体は取得できないという考えです。
特性にコンパニオン オブジェクトを与えてみてください。コンパニオン オブジェクトは、 のインスタンスを返すオブジェクトになりますAType
。
コンパニオン オブジェクトを使用する場合:
trait Queue[T]{
def head:T
def tail:Queue[T]
def enqueue(x:T):Queue[T]
}
object Queue{
def apply[T](xs: T*): Queue[T] =
new QueueImpl[T](xs.toList)
private class QueueImpl[T](
private val leading:List[T],
private val trailing:List[T]=Nil
) extends Queue[T]
{
// methods in here
}
}
多分これはもっと簡単です:
object A{
def aType(...):A = new B(...)
def aType(...):A = new C(...)
/* classes */
private class C(...) extends A
private class B(...) extends A{
// blah blah
}
}
特定のタイプのインスタンスを作成する最も一般的な方法は、コメントで言及されている @bluenote10 のようにファクトリ スタイルを使用することです。
そのために、最初にファクトリ定義を作成します
// factory definition
trait CanCreateInstance[T] {
def create: T
}
次に、私たちのクラスでは、その特定のタイプのファクトリを要求します
class Foo[T <: A](implicit factory: CanCreateInstance[T]) {
def newT: T = factory.create
}
のコンパニオン オブジェクトにいくつかのデフォルト ファクトリを追加できます。CanCreateInstance
object CanCreateInstance {
// define default availble instance creators
implicit def bFactory = new CanCreateInstance[B] {
def create = new B
}
}
次に、このように簡単に使用できます
val fooB = new Foo[B]
val newB = fooB.newT
Foo
別の型のインスタンスを作成できるようにする必要がある場合は、単純にファクトリを提供できます。
implicit val cFactory = new CanCreateInstance[C] {
def create = new C
}
val fooC = new Foo[C]
val newC = fooC.newT
Foo
この構成により、デフォルトのファクトリが利用できない場合、任意のユーザーがファクトリを提供できます。たとえば、工場を提供することもできA
ます
implicit val aFactory = new CanCreateInstance[A] {
def create = new A {}
}
ファクトリを作成せずに実行時に不明なタイプからインスタンスを作成する必要がある場合は、TypeTag
. これに関する情報は、Scala: What is a TypeTag and how do I use it? にあります。