6

Cecha TraversableLike[+A, +Repr] pozwala utworzyć kolekcję, w której niektóre funkcje zwrócą Repr, podczas gdy inne będą nadal zwracać parametr typu That w funkcji. Czy istnieje sposób zdefiniowania CustomCollection[A], gdzie funkcje takie jak map, ++ i inne będą domyślnie jako Repr, jeśli nie zostały w inny sposób określone?Tworzenie niestandardowej kolekcji scala, w której mapa domyślnie zwraca kolekcję niestandardową?

Oto fragment kodu, który mam nadzieję, że opisuje to, co lubię:

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 
} 

Chciałbym ostatnią linię być CustomCollection(2, 3, 4).

+0

Zalogowałem się tylko do +1 OM-nom-nom za to, że tylko trzech minut tył postu. Wydaje się, że nie ma "Terminowej edycji!" przycisk z logo kciuka w górę. –

Odpowiedz

4

Musisz skonfigurować obiekt towarzysz, który zapewnia wyrafinowaną CanBuildFrom instancję:

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

Świetna odpowiedź! Miałem wrażenie, że potrzebuję użyć cbf, ale nie mogłem znaleźć najbardziej ogólnego sposobu na zrobienie tego. Czy jest gdziekolwiek mogę przeczytać więcej na temat specyfiki api kolekcji w ten sposób? To znaczy. skąd mam wiedzieć, że oprócz rozszerzenia 'TraversableLike' muszę również rozszerzyć' GenericTraversableTemplate'? –

+0

@ dicarlo2 - Generalnie patrzę na kod źródłowy klasy najbardziej podobnej do tego, co robię i skopiuję to, co wymieszali. Stwierdziłem, że jest to bardziej wiarygodne niż jakiekolwiek inne podejście w przypadku braku wiedzy o tym, która funkcja jest dostępna przez każdą cechę (i sposób, w jaki chcesz rozwiązać wszystkie wzorce dziedziczenia kształtu rombu). –

+0

@RexKerr Heh, to jest to samo, co zwykle robię, po opublikowaniu pytania dotarłem do 'TraversableFactory' zanim musiałem odejść od komputera, wciąż kto wie, ile plików obejrzałbym, aby znaleźć wszystkie wzorce dziedziczenia w kształcie diamentu. Szkoda, że ​​nie ma lepszego odniesienia, a dokumentacja nie zawsze pokazuje, jakie są relacje między poszczególnymi cechami. –