【问题标题】:Require Type to be Instantiatable, ie not a trait/abstract要求类型是可实例化的,即不是特征/抽象
【发布时间】:2013-02-08 07:51:05
【问题描述】:

说我有:

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 本身。

【问题讨论】:

  • 恕我直言,实现这一点的最常见方法不是要求可以实例化类型,而是使用工厂。例如,您可以将工厂传递给Foo 的构造函数,该工厂可用于在Foo 内构造新的As。这简化了设计,因为您不必关心A 是抽象的还是A 的某个可实例化子类型,您只需要知道如何构造它。
  • @ultramiraculous -- 不可能完全按照你的要求去做。

标签: scala mixins


【解决方案1】:

尝试给 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
  }

}

【讨论】:

    【解决方案2】:

    创建给定类型实例的最常用方法是使用工厂样式,如 cmets 中提到的 @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?

    【讨论】:

      猜你喜欢
      • 2013-03-07
      • 1970-01-01
      • 2013-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多