Определение параметров кругового типа в scala - PullRequest
4 голосов
/ 13 января 2010

Я пытаюсь определить универсальный контейнер, элементы которого могут возвращать вмещающий контейнер. Что-то вроде:

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
}

Однако этот фрагмент не компилируется, поскольку я должен задать параметр типа для Element в определении abstract class Container[E <: Element] и тип для Container в определении abstract class Element[C <: Container].

Есть ли способ добиться поведения, которое я ищу? Есть ли соответствующее объявление для Container и Element? Должен ли я определять сторонний объект?

Ответы [ 3 ]

6 голосов
/ 14 января 2010

Другие уже упомянутые решения не обеспечивают соответствие типов: то есть, учитывая тип 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
  }
}
6 голосов
/ 13 января 2010
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
}
5 голосов
/ 13 января 2010

Использование членов типа вместо параметров типа позволит избежать проблемы:

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
}
...