2010-01-13 7 views
4

J'essaie de définir un conteneur générique dont les éléments peuvent renvoyer le conteneur englobant. Quelque chose comme:Définition des paramètres de type circulaire dans scala

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 
} 

Cependant cet extrait ne compile pas parce que je devrais donner un paramètre de type à Element dans la définition abstract class Container[E <: Element] et un type à Container dans la définition abstract class Element[C <: Container].

Y a-t-il un moyen d'atteindre le comportement que je recherche? Y a-t-il une déclaration appropriée pour Container et Element? Dois-je définir un objet tiers?

+0

estimation grossière que je ne peux pas ouvrir mon compilateur à la minute, mais avez-vous essayé 'classe abstraite élément [C <: Container [élément]] 'ou quelque chose de similaire? – wheaties

+0

Oui, mais alors 'Element' a aussi besoin d'un type de paramètre ... – paradigmatic

+0

'addNewElement()' ne devrait-il pas prendre un élément à ajouter? C'est, 'addNewElement (e: E)'? –

Répondre

6

Les autres solutions déjà données ne parviennent pas à appliquer que les types correspondent: à savoir, étant donné un type ContainerImpl extends Container, vous devriez être Assurez-vous que ContainerImpl.E.C doit être ContainerImpl et non un autre conteneur. Voici celui qui fait appliquer cette (adapté de 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
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

utilisant des éléments de type au lieu des paramètres de type éviterait la question:

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 
}