2011-01-07 8 views
5

Próbuję zdefiniować niestandardowy interfejs kolekcji w Scala 2.8. Chcę wymagać, aby podklasy były Traversable, a także inne zachowania. Chcę również podobne metody mapie(), aby przywrócić odpowiedni typ, jak poniżej:Jak zdefiniować niestandardowy interfejs kolekcji w Scali bez definiowania implementacji?

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

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

nie skompilować, ponieważ CustomCollection.map() zwraca przesuwny. Przypuszczam, że muszę zdefiniować CanBuildFrom, ale muszę zdefiniować metodę apply(), która tworzy instancję od zera. Nie chcę określać sposobu konstruowania tego; to powinno należeć do realizatora. czy to możliwe?

Odpowiedz

5

Jeśli chcesz map powrócić bardziej konkretny typ kolekcji, to należy również dziedziczyć TraversableLike, z drugiego parametru type (typ reprezentacja) ustawionym na CustomCollection[A].

Następnie wymagany jest domyślny parametr typu CanBuildFrom. Będzie wyglądać w obiekcie towarzyszącym z CustomCollection, aby znaleźć zgodną niejawną wartość tego typu. Jeśli spojrzysz na kod źródłowy klas Seq, zobaczysz, że ich obiekty towarzyszące udostępniają obiekty CanBuildFrom typu GenericCanBuildFrom, które przekazują wywołanie budowniczego z powrotem do kolekcji, która zażądała budowania. W ten sposób dynamiczny typ sposobu zwracania transformatorów Seq (na przykład map) jest zawsze taki sam jak typ samej sekwencji.

Co trzeba zrobić, to:

  1. Bądź CustomCollection[A] dziedziczą TraversableLike
  2. Bądź CustomCollection[A] dziedziczyć GenericTraversableTemplate
  3. Zrób obiektu towarzysz CustomCollection i dodać niejawna, która zwraca GenericCanBuildFrom
  4. zapewnić domyślna implementacja dla konstruktora w

Realizatorzy CustomCollection będzie musiał dostarczyć obiektów towarzyszących, które mają implementacje budowniczym i ukryte CanBuildFrom przedmiotów (które mogą być po prostu GenericCanBuildFrom s).

EDIT:

GenericTraversablTemplate wspomniano powyżej jest potrzebne, ponieważ pierwszy sprawia, że ​​kolekcja będzie mieć metodę genericBuilder zwany przez fabrykę GenericCanBuildFrom konstruktora. Po drugie, zapewnia, że ​​kolekcja faktycznie ma obiekt towarzyszący typu GenericCompanion.

+0

Dzięki, axel22. Jeśli rozumiem twoją odpowiedź, muszę podać domyślną implementację CustomCollection, która będzie używana przez metodę newBuilder mojego kompana. Miałem nadzieję uniknąć określenia domyślnej implementacji. Czy mógłbyś wyjaśnić, dlaczego go potrzebuję? Wydaje się, że nie powinno to być konieczne dla metody takiej jak map(), ponieważ nie można wywołać metody map(), chyba że masz już jakieś implementacje. – traversable

+1

Z technicznego punktu widzenia można uniknąć dostarczenia domyślnej implementacji buildera w pakiecie 'CustomCollection', ale w jaki sposób zaimplementować metodę bez parametrów' apply() 'w' CanBuildFrom'? Możesz pozwolić, aby 'newBuilder' w elemencie' CustomCollection' wyświetlał nieobsługiwany wyjątek operacji, co pozwoli uniknąć domyślnej implementacji.Wierzę, że wszystko by wtedy działało, z wyjątkiem metody 'breakOut' w kolekcjach, która wymaga bez parametrycznego' apply() '.. – axel22

+0

Ah ... więc powodem, dla którego potrzebuję domyślnej implementacji, jest wykonanie operacji breakOut. Dzięki! – traversable