【问题标题】:Circular type parameters definition in scalascala中的循环类型参数定义
【发布时间】:2011-01-04 19:12:53
【问题描述】:

我正在尝试定义一个通用容器,其元素可以返回封闭容器。比如:

abstract class Container[E <: Element] { // compile error
  def contains( e: E ): Boolean
  def addNewElement(): Unit
}

abstract class Element[C <: Container] { // compile error
  def enclosingContainer(): C
}

class MyContainer extends Container[MyElement] {
  private var elements = List[MyElement]()
  override def contains( elem: MyElement ) = elements.contains( elem )
  override def addNewElement() { elements ::= new MyElement(this) }
}

class MyElement( container: MyContainer ) extends Element[MyContainer] {
  override val enclosingContainer = container
}

但是,sn-p 无法编译,因为我应该在abstract class Container[E &lt;: Element] 定义中为Element 提供一个类型参数,在abstract class Element[C &lt;: Container] 定义中为Container 提供一个类型。

我有办法实现我正在寻找的行为吗? ContainerElement 是否有适当的声明?我应该定义第三方对象吗?

【问题讨论】:

  • 粗略的猜测,因为我现在无法打开我的编译器,但你尝试过abstract class Element[C &lt;: Container[Element]] 或类似的东西吗?
  • 是的,但是Element 也需要一个参数类型...
  • 不应该addNewElement() 带一个元素来添加吗?即addNewElement(e : E)?
  • @Alexey 在这个例子中没有。在我的实际应用程序中,它采用另一种类型的实例并将其包装在正确初始化的新元素对象中。

标签: scala generics type-parameter


【解决方案1】:

已经给出的其他解决方案无法强制类型匹配:也就是说,给定类型ContainerImpl extends Container,您应该确保ContainerImpl.E.C 应该是ContainerImpl 而不是其他容器。这是一个执行此操作的方法(改编自 http://programming-scala.labs.oreilly.com/ch13.html):

abstract class ContainerWithElement {
  type C <: Container
  type E <: Element

  trait Container {
    self: C =>
    def contains( e: E ): Boolean
    def addNewElement(): Unit
  }

  trait Element {
    self: E =>
    def enclosingContainer(): C
  }
}

【讨论】:

    【解决方案2】:
    abstract class Container[E <: Element[_]] {
      def contains( e: E ): Boolean
      def addNewElement(): Unit
    }
    
    abstract class Element[C <: Container[_]] {
      def enclosingContainer(): C
    }
    
    class MyContainer extends Container[MyElement] {
      private var elements = List[MyElement]()
      override def contains( elem: MyElement ) = elements.contains( elem )
      override def addNewElement() { elements ::= new MyElement(this) }
    }
    
    class MyElement( container: MyContainer ) extends Element[MyContainer] {
      override val enclosingContainer = container
    }
    

    【讨论】:

      【解决方案3】:

      使用类型成员而不是类型参数可以避免这个问题:

      abstract class Container { // compile error
        type E <: Element
        def contains( e: E ): Boolean
        def addNewElement(): Unit
      }
      
      abstract class Element { // compile error
        type C <: Container
        def enclosingContainer(): C
      }
      
      class MyContainer extends Container {
        type E = MyElement
        private var elements = List[MyElement]()
        override def contains( elem: MyElement ) = elements.contains( elem )
        override def addNewElement() { elements ::= new MyElement(this) }
      }
      
      class MyElement( container: MyContainer ) extends Element {
        type C = MyContainer
        override val enclosingContainer = container
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-01
        • 1970-01-01
        • 2023-02-02
        • 2015-09-05
        • 2010-11-18
        • 1970-01-01
        • 2011-11-05
        相关资源
        最近更新 更多