是否可以像旧的 CanBuildFrom 那样隐式获取集合的构建器?
Is it possible to implicitly get a builder for a collection, as in the old CanBuildFrom?
我有一些旧代码依赖隐式 CanBuildFrom
来构建指定为类型参数的类型的集合。从 2.12 开始,在新的集合库中,替换 BuildFrom
不提供无参数 Builder
工厂方法。我想要的是集合的 IterableFactory
,但这些是伴随对象,不是隐含的。 我能以某种方式移植它而不引入我自己的隐式工厂 class 为库中的每个集合 class 包装一个 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)
标准库中为 String
和 Array
提供了单独的隐式 Factory
。对于所有 Iterable
s(List
、Map
、Set
等)它都有效,因为 Iterable
s 的伴随对象扩展了 IterableFactory
class,提供了一个implicit def iterableFactory[A]: Factory[A, CC[A]]
方法。
我有一些旧代码依赖隐式 CanBuildFrom
来构建指定为类型参数的类型的集合。从 2.12 开始,在新的集合库中,替换 BuildFrom
不提供无参数 Builder
工厂方法。我想要的是集合的 IterableFactory
,但这些是伴随对象,不是隐含的。 我能以某种方式移植它而不引入我自己的隐式工厂 class 为库中的每个集合 class 包装一个 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)
标准库中为 String
和 Array
提供了单独的隐式 Factory
。对于所有 Iterable
s(List
、Map
、Set
等)它都有效,因为 Iterable
s 的伴随对象扩展了 IterableFactory
class,提供了一个implicit def iterableFactory[A]: Factory[A, CC[A]]
方法。