У меня есть старый код, который полагался на неявный CanBuildFrom
для создания коллекции типа, указанного в качестве параметра типа. Начиная с версии 2.12, в новой библиотеке коллекций замена BuildFrom
не предлагает фабричный метод без аргументов Builder
. То, что я хочу, это IterableFactory
для коллекции, но это сопутствующие объекты, которые не являются неявными. Могу ли я как-то портировать его, не вводя свой собственный неявный фабричный класс, обертывающий Factory
для каждого класса коллекции в библиотеке? Я знаю, что у этих фабрик есть много разновидностей, но даже если бы мне пришлось добавить особый случай для тех, кто принимает неявные доказательства, это все равно было бы намного лучше, чем то, что у меня есть.
Разумной альтернативой в новом коде, вероятно, было бы использование IterableFactory
в качестве аргумента (значение) вместо того, чтобы полагаться на явные аргументы типа, но это потребовало бы изменений в слишком многих местах, поэтому я предпочел бы придерживаться текущей архитектуры и сделать шаблон.
Вы можете использовать аргументы типа вместо неявных.
def listToString[A, CC[x] <: Iterable[x]](
list: collection.IterableOps[A, CC, CC[A]]
): CC[String] =
list.map(x => x.toString)
listToString(List(1, 2, 3, 4))
-> List(1, 2, 3, 4): List[String]
listToString(Set("foo", "bar", "baz"))
-> Set(foo, bar, baz): scala.collection.immutable.Set[String]
Если вы хотите создать общую коллекцию поэлементно с помощью Builder
и без существующей ранее коллекции, вы можете использовать неявный аргумент Factory. Например:
import scala.collection.Factory
class Filler[T](makeElement: Int => T) {
def apply[C[_]](n: Int)(implicit factory: Factory[T, C[T]]): C[T] = {
val builder = factory.newBuilder
for (i <- 1 to n) builder += makeElement(i)
builder.result()
}
}
И вы можете использовать его следующим образом:
scala> val fill = new Filler(_.toString)
fill: Filler[String] = Filler@154f8280
scala> fill[Vector](10)
res0: Vector[String] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> fill[Set](10)
res1: Set[String] = HashSet(8, 4, 9, 5, 10, 2, 7, 3, 6, 1)
scala> fill[Array](10).toSeq
res2: Seq[String] = ArraySeq(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
В стандартной библиотеке есть отдельные неявные Factory
для String
и Array
. И для всех Iterable
(List
, Map
, Set
и т. д.) это работает, потому что сопутствующие объекты Iterable
расширяют класс IterableFactory, который предоставляет метод implicit def iterableFactory[A]: Factory[A, CC[A]]
.
Я чувствую себя идиотом. Я не знаю, что я сделал не так, потому что я был уверен, что пробовал это. Может быть, попросили неявный IterableFactory
? Ок - спасибо!
Это помогает? stackoverflow.com/questions/56551015/…