【发布时间】:2019-10-20 10:15:38
【问题描述】:
我希望能够对T[_] <: Traversable 之类的类型进行通用操作,以便我可以执行映射和过滤等操作,但我想尽可能推迟决定选择哪个Traversable .
我希望能够针对通用T[Int] 编写函数,返回T[Int] 而不是Traversable[Int]。因此,例如,我想将一个函数应用于 Set[Int] 或 Vector[Int] 或任何扩展 Traversable 并取回该类型的东西。
我首先尝试以一种简单的方式来做到这一点,例如:
trait CollectionHolder[T[_] <: Traversable[_]] {
def easyLessThanTen(xs: T[Int]): T[Int] = {
xs.filter(_ < 10)
}
}
但这不会编译:缺少扩展函数的参数类型。但是,如果函数采用Traversable[Int] 而不是T[Int],它将编译,所以我认为我可以使用Traversable 并转换为T。这将我引向CanBuildFrom
object DoingThingsWithTypes {
trait CollectionHolder[T[_] <: Traversable[_]] {
def lessThanTen(xs: T[Int])(implicit cbf: CanBuildFrom[Traversable[Int], Int, T[Int]]): T[Int] = {
val filteredTraversable = xs.asInstanceOf[Traversable[Int]].filter(_ < 10)
(cbf() ++= filteredTraversable).result
}
编译。但是在我的测试中:
val xs = Set(1, 2, 3, 4, 1000)
object withSet extends CollectionHolder[Set]
withSet.lessThanTen(xs) shouldBe Set(1, 2, 3, 4)
我收到以下编译器错误:
无法构造带有类型元素的 Set[Int] 类型的集合 Int 基于 Traversable[Int] 类型的集合。不够 方法lessThanTen的参数:(隐式cbf: scala.collection.generic.CanBuildFrom[Traversable[Int],Int,Set[Int]])Set[Int]。 未指定值参数cbf。
我在哪里可以获得 CanBuildFrom 来进行此转换?或者更好的是,我怎样才能修改我更简单的方法以获得我想要的结果?或者我是否需要使用类型类并为我感兴趣的每个 Traversable 编写一个隐式实现(一个用于 Set,一个用于 Vector 等)?如果可能的话,我宁愿避免使用最后一种方法。
【问题讨论】:
-
我建议使用更高的抽象,例如
Functortypeclass。 -
你能稍微扩展一下这个想法吗?
-
我的意思是,而不是尝试使用集合库和构建以及所有这些。您可以只使用
Functor.map之类的方式编写代码。如果你没有这方面的经验,你可以从阅读 scala-with-cats 开始。此外,如果您可以提供一个包含您需要的所有方法的具体示例,我将能够提供一个实现。 -
最终的实现将有相当多的方法使用诸如:filter、exists 和 nonEmpty(因此使用 Traversable)。如果我需要为我将使用的每个 Traversable(Set、Vector 等)编写一个新的类型类,那么对于每个函数,我似乎不妨将它们保留为抽象并为每个可遍历实现所有内容。我希望大部分函数都建立在少量抽象函数之上,所以为新类型实现这个只意味着编写少量函数,其余的都是免费的。
标签: scala generics scala-collections type-parameter