6

Il tratto TraversableLike[+A, +Repr] consente di creare una raccolta in cui le funzioni alcune restituiscono un Repr, mentre altre continuano a restituire il parametro di tipo That sulla funzione. C'è un modo per definire un CustomCollection[A] in cui funzioni come map, ++ e altre saranno predefinite That come Repr se non diversamente indicato?Creare una collezione di scala personalizzata in cui la mappa è impostata per restituire la raccolta personalizzata?

Ecco un frammento di codice che si spera descrive quello che vorrei:

case class CustomCollection[A](list: List[A]) extends TraversableLike[A, CustomCollection[A]] { 
    protected[this] def newBuilder = new CustomCollectionBuilder[A] 
    def foreach[U](f: (A) => U) {list foreach f} 
    def seq = list 
} 

class CustomCollectionBuilder[A] extends mutable.Builder[A, CustomCollection[A]] { 
    private val list = new mutable.ListBuffer[A]() 
    def += (elem: A): this.type = { 
    list += elem 
    this 
    } 
    def clear() {list.clear()} 
    def result(): CustomCollection[A] = CustomCollection(list.result()) 
} 

object CustomCollection extends App { 
    val customCollection = CustomCollection(List(1, 2, 3)) 
    println(customCollection filter {x => x == 1}) // CustomCollection(1) 
    println(customCollection map {x => x + 1}) // non-empty iterator 
} 

Vorrei l'ultima riga di essere CustomCollection(2, 3, 4).

+0

mi sono collegato solo a +1 om-nom-nom per essere a soli tre minuti dietro il palo. Non sembra essere una "Modifica attuale!" pulsante con un pollice in alto logo. –

risposta

4

È necessario impostare un oggetto associato che fornisce la raffinata CanBuildFrom esempio:

import collection.TraversableLike 
import collection.generic.{CanBuildFrom, GenericCompanion, GenericTraversableTemplate, 
    TraversableFactory} 
import collection.mutable.{Builder, ListBuffer} 

object CustomCollection extends TraversableFactory[CustomCollection] { 
    def newBuilder[A] = new CustomCollectionBuilder[A] 
    implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, CustomCollection[A]] = 
    new CanBuildFrom[Coll, A, CustomCollection[A]] { 
     def apply(): Builder[A, CustomCollection[A]] = new CustomCollectionBuilder() 
     def apply(from: Coll): Builder[A, CustomCollection[A]] = apply() 
    } 
} 
case class CustomCollection[A](list: List[A]) extends Traversable[A] 
with TraversableLike[A, CustomCollection[A]] 
with GenericTraversableTemplate[A, CustomCollection] { 
    override def companion: GenericCompanion[CustomCollection] = CustomCollection 
    def foreach[U](f: A => U) { list foreach f } 
    override def seq = list 
} 

class CustomCollectionBuilder[A] extends Builder[A, CustomCollection[A]] { 
    private val list = new ListBuffer[A]() 
    def += (elem: A): this.type = { 
    list += elem 
    this 
    } 
    def clear() {list.clear()} 
    def result(): CustomCollection[A] = CustomCollection(list.result()) 
} 

val customCollection = CustomCollection(List(1, 2, 3)) 
val f = customCollection filter {x => x == 1} // CustomCollection[Int] 
val m = customCollection map {x => x + 1}  // CustomCollection[Int] 
+0

Ottima risposta! Avevo la sensazione di aver bisogno di usare un cbf, ma non riuscivo a trovare il modo più generico per farlo. C'è un posto dove posso leggere di più sulle specifiche delle collezioni come questa? Cioè come devo sapere che oltre ad estendere 'TraversableLike' ho anche bisogno di estendere' GenericTraversableTemplate'? –

+0

@ dicarlo2 - In genere guardo il codice sorgente della classe più simile a quello che sto facendo e copio ciò che hanno mescolato. Ho trovato questo più affidabile di qualsiasi altro approccio in assenza di sapere esattamente quale funzionalità è fornita per ogni tratto (e come vuoi che siano risolti tutti i modelli di ereditarietà a forma di diamante). –

+0

@RexKerr Heh, è ​​la stessa cosa che faccio di solito, dopo aver postato la domanda che mi è arrivata fino a "TraversableFactory" prima di dovermi allontanare dal computer, ancora chissà quanti file avrei guardato attraverso per trovare tutti i modelli di ereditarietà a forma di diamante. Peccato che non ci sia un riferimento migliore e la documentazione non sempre illumina quali siano le relazioni tra ogni tratto. –