3

说我有:

trait A

class B extends A

class C extends A

有没有办法配置类型参数,例如:

class Foo[AType <: A with canCreateInstance]
    def newAType : AType = new AType

这个想法是 Foo 只能采用实现 A 的类,如 B 或 C,但不能采用 A 本身。

4

2 回答 2

0

创建给定类型实例的最常见方法是使用工厂样式,如注释中提到的@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:什么是 TypeTag 以及如何使用它?

于 2013-02-23T12:56:30.160 回答
0

尝试给 trait 一个伴生对象。伴生对象将是返回 的实例的对象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
  }

}
于 2013-02-22T16:58:53.670 回答