Один из самых мощных шаблонов, доступных в Scala, - это шаблон обогащения-my-library *, который использует неявные преобразования для добавления методов к существующим классам без необходимости разрешения динамического метода. Например, если бы мы пожелали, чтобы все строки имели метод spaces
, который подсчитывал, сколько пробельных символов они имели, мы могли бы:
class SpaceCounter(s: String) {
def spaces = s.count(_.isWhitespace)
}
implicit def string_counts_spaces(s: String) = new SpaceCounter(s)
scala> "How many spaces do I have?".spaces
res1: Int = 5
К сожалению, этот шаблон сталкивается с трудностями при работе с коллекциями. Например, задан ряд вопросов о группировании элементов последовательно с коллекциями. В одном снимке ничего не создано, поэтому это кажется идеальным кандидатом для шаблона обогащения my-library с использованием общей коллекции C
и типа универсального элемента A
:
class SequentiallyGroupingCollection[A, C[A] <: Seq[A]](ca: C[A]) {
def groupIdentical: C[C[A]] = {
if (ca.isEmpty) C.empty[C[A]]
else {
val first = ca.head
val (same,rest) = ca.span(_ == first)
same +: (new SequentiallyGroupingCollection(rest)).groupIdentical
}
}
}
кроме, конечно, он не работает. REPL сообщает нам:
<console>:12: error: not found: value C
if (ca.isEmpty) C.empty[C[A]]
^
<console>:16: error: type mismatch;
found : Seq[Seq[A]]
required: C[C[A]]
same +: (new SequentiallyGroupingCollection(rest)).groupIdentical
^
Есть две проблемы: как мы получаем C[C[A]]
из пустого списка C[A]
(или из воздуха)? И как мы получаем C[C[A]]
обратно из строки same +:
вместо Seq[Seq[A]]
?
* Раньше была известна как сутенер-моя библиотека.