2011-01-07 13 views
5

Ich versuche, eine benutzerdefinierte Sammlung Schnittstelle in Scala 2.8 zu definieren. Ich möchte, dass Unterklassen Traversable, plus ein anderes Verhalten sind. Ich möchte auch Methoden wie map() den entsprechenden Typ zurückzukehren, wie unten:Wie definiere ich eine benutzerdefinierte Sammlung Schnittstelle in Scala, ohne eine Implementierung zu definieren?

trait CustomCollection[+A] extends Traversable[A] { 
    def customOperation(i:Int):Int // for example 
} 

def incrementAll(c:CustomCollection[Int]):CustomCollection[Int] = c.map { _ + 1 } 

Dies gilt nicht kompilieren, weil CustomCollection.map() eine Traverszurückgibt. Ich denke, ich muss ein CanBuildFrom definieren, aber dann muss ich eine apply() -Methode definieren, die eine Instanz von Grund auf neu erstellt. Ich möchte keinen Weg geben, dies zu konstruieren; das sollte dem Implementierer überlassen bleiben. Ist das möglich?

Antwort

5

Wenn Sie möchten, dass map einen spezifischeren Auflistungstyp zurückgibt, sollten Sie auch TraversableLike erben, wobei der zweite Typparameter (Darstellungstyp) auf CustomCollection[A] festgelegt wird.

Als nächstes benötigt map einen impliziten Parameter vom Typ CanBuildFrom. Es wird im Begleitobjekt von CustomCollection nach einem übereinstimmenden impliziten Wert dieses Typs suchen. Wenn Sie sich den Quellcode der Klassen Seq ansehen, sehen Sie, dass ihre Partner CanBuildFrom Objekte vom Typ GenericCanBuildFrom bereitstellen, die den Aufruf des Builders an die Sammlung zurückgeben, die den Builder angefordert hat. Auf diese Weise ist der dynamische Typ des Rückgabetyps von Seq Transformatormethoden (z. B. map) immer der gleiche wie der Typ der Sequenz selbst.

Was haben Sie zu tun ist:

  1. Machen CustomCollection[A] inherit TraversableLike
  2. CustomCollection[A]GenericTraversableTemplate erben Make
  3. ein Begleitobjekt der CustomCollection Make und ein implizites hinzufügen, die gibt eine GenericCanBuildFrom
  4. ein Geben Standardimplementierung für den Builder in der CustomCollection Begleiter

Die Implementierer von CustomCollection müssen Companion-Objekte bereitstellen, die Builder-Implementierungen und implizite CanBuildFrom Objekte haben (die einfach GenericCanBuildFrom s sein können).

EDIT:

GenericTraversablTemplate oben erwähnt ist erforderlich, da es sicherstellt, dass die erste Sammlung der genericBuilder Methode der GenericCanBuildFrom builder Fabrik genannt haben. Zweitens stellt es sicher, dass die Sammlung tatsächlich das Begleitobjekt vom Typ GenericCompanion hat.

+0

Danke, axel22. Wenn ich Ihre Antwort verstanden habe, muss ich eine Standardimplementierung von CustomCollection bereitstellen, die von der newBuilder-Methode meines Companion verwendet wird. Ich hatte gehofft zu vermeiden, eine Standardimplementierung anzugeben. Könnten Sie näher erläutern, warum ich einen brauche? Es scheint nicht so, dass es für eine Methode wie map() notwendig sein sollte, weil Sie map() nur aufrufen können, wenn Sie bereits eine Implementierung haben. – traversable

+1

Technisch gesehen könnten Sie es vermeiden, eine Standard-Builder-Implementierung im Compiler "CustomCollection" bereitzustellen, aber wie implementieren Sie dann die Methode "apply()" ohne Parameter in "CanBuildFrom"? Sie können zulassen, dass 'newBuilder' im Companion' CustomCollection' eine nicht unterstützte Operation ausgibt, wodurch eine Standardimplementierung vermieden wird.Ich glaube, dann würde alles funktionieren, bis auf die 'breakOut'-Methode in Sammlungen, die das parameterlose 'apply()' benötigt. – axel22

+0

Ah ... also der Grund, warum ich eine Standardimplementierung brauche, ist, dass breakOut funktioniert. Vielen Dank! – traversable